makaron-cli 0.11.1 → 0.11.3

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.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "AI image editing, video generation, music creation, and marketplace skill workflows via CLI. Agents can self-register, install skills, create projects, and produce creative media.",
5
5
  "author": {
6
6
  "name": "Makaron AI",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "AI image editing, video generation, music creation, and marketplace skill workflows via CLI. Agents can self-register, install skills, create projects, and produce creative media.",
5
5
  "displayName": "Makaron",
6
6
  "shortDescription": "AI image/video/music creation from the terminal",
package/README.md CHANGED
@@ -238,6 +238,7 @@ npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
238
238
  # 3a. Submit image-to-video rendering (images must be public URLs from step 1 or uploaded)
239
239
  npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --model kling
240
240
  npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> slow cinematic push-in with native ambience" --image https://...jpg --duration 5 --model grok
241
+ 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 --model seedance-mini --video-resolution 480p --aspect 9:16
241
242
 
242
243
  # 3b. Edit a video from a local file or public URL
243
244
  npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance-fast
@@ -253,9 +254,9 @@ For project/timeline video editing, use:
253
254
  npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
254
255
  ```
255
256
 
256
- Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--model seedance-fast|seedance|kling|grok`, `--video-resolution auto|480p|720p|1080p|4k`. Default model is `seedance-fast`. SeeDance accepts integer output duration 4-15s (default 5s); Kling supports 5-15s; Grok 1.5 supports 1-15s single-image-to-video only. For `--model grok`, forced `--aspect` is ignored to avoid xAI stretching the source image; pad/create the image at the target shape first or use another model.
257
+ Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--model seedance-fast|seedance-mini|seedance|kling|grok`, `--video-resolution auto|480p|720p|1080p|4k`. Default model is `seedance-fast`. SeeDance accepts integer output duration 4-15s (default 5s); `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests; Kling supports 5-15s; Grok 1.5 supports 1-15s single-image-to-video only. For `--model grok`, forced `--aspect` is ignored to avoid xAI stretching the source image; pad/create the image at the target shape first or use another model.
257
258
 
258
- Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance-fast --video` or `--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. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s. Grok does not support video references.
259
+ Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance-fast --video`, `--model seedance-mini --video`, or `--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. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s. Grok does not support video references.
259
260
 
260
261
  ### `music` — Music generation
261
262
 
package/bin/makaron.mjs CHANGED
@@ -276,7 +276,7 @@ Options:
276
276
  --video <file|url> Attach a video to the project timeline. Repeatable.
277
277
  --skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
278
278
  --model <name> Preferred image/model route.
279
- --video-model <name> Preferred video model: seedance-fast, seedance, kling, or grok.
279
+ --video-model <name> Preferred video model: seedance-fast, seedance-mini, seedance, kling, or grok.
280
280
  --video-resolution <res> Video resolution: auto, 480p, 720p, 1080p, or 4k.
281
281
  --background, -b Submit and print a runId.
282
282
  --json Output structured JSON.
@@ -1031,6 +1031,25 @@ async function uploadFileViaSignedUrl(baseUrl, headers, projectId, filePath, con
1031
1031
  return publicUrl;
1032
1032
  }
1033
1033
 
1034
+ async function uploadImageFilesViaSignedUrl(baseUrl, headers, projectId, imagePaths) {
1035
+ const urls = [];
1036
+ for (const imagePath of imagePaths) {
1037
+ const valid = validateImage(imagePath);
1038
+ if (!valid.ok) {
1039
+ process.stderr.write(`❌ Cannot upload: ${path.basename(imagePath)}\n ${valid.error}\n`);
1040
+ process.exit(1);
1041
+ }
1042
+ process.stderr.write(`📤 Uploading ${path.basename(imagePath)}...\n`);
1043
+ const url = await uploadFileViaSignedUrl(baseUrl, headers, projectId, imagePath, valid.mime);
1044
+ if (!url) {
1045
+ process.stderr.write(`❌ Failed to upload image: ${imagePath}\n`);
1046
+ process.exit(1);
1047
+ }
1048
+ urls.push(url);
1049
+ }
1050
+ return urls;
1051
+ }
1052
+
1034
1053
  function imageToArg(imgPath) {
1035
1054
  if (imgPath.startsWith('http://') || imgPath.startsWith('https://')) return imgPath;
1036
1055
  return readImageAsDataUrl(imgPath);
@@ -1334,12 +1353,12 @@ Use with chat:
1334
1353
  console.log('Usage: makaron analyze --video <file|url> ["question"]');
1335
1354
  } else if (topic === 'video') {
1336
1355
  if (subtopic === 'script') console.log('Usage: makaron video script --image <file> [--image <file>] [--lang en|zh] "direction"');
1337
- else if (subtopic === 'create') console.log('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model seedance-fast|seedance|kling|grok] [--video-resolution auto|480p|720p|1080p|4k] [--keep-original-sound]');
1356
+ else if (subtopic === 'create') console.log('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model seedance-fast|seedance-mini|seedance|kling|grok] [--video-resolution auto|480p|720p|1080p|4k] [--keep-original-sound]');
1338
1357
  else if (subtopic === 'status') console.log('Usage: makaron video status <taskId> | --snapshot <snapshotId> [--wait]');
1339
1358
  else console.log(`Video commands:
1340
1359
  video script --image <file> [--image <file>] "direction" Write video script
1341
1360
  video create --script "..." --image <url> [--duration 10] Submit video task
1342
- video create --script "..." --video <public-url> [--model seedance-fast|seedance|kling] Edit a video (standalone; Grok does not support video refs)
1361
+ video create --script "..." --video <public-url> [--model seedance-fast|seedance-mini|seedance|kling] Edit a video (standalone; Grok does not support video refs)
1343
1362
  video status <taskId> Check video status
1344
1363
  video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
1345
1364
  `);
@@ -1462,52 +1481,28 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1462
1481
 
1463
1482
  // --project auto: create a new project (with images/videos if provided)
1464
1483
  if (!projectId || projectId === 'auto') {
1465
- if (chatImages.length === 0) {
1466
- // Create empty project (videos will be uploaded separately after)
1467
- process.stderr.write(`📦 Creating new project...\n`);
1468
- const res = await fetch(`${baseUrl}/api/projects/create`, {
1469
- method: 'POST',
1470
- headers: { 'Content-Type': 'application/json', ...headers },
1471
- body: JSON.stringify({ title: prompt.slice(0, 50) }),
1472
- });
1473
- if (!res.ok) { process.stderr.write(`❌ Failed to create project: ${await res.text()}\n`); process.exit(1); }
1474
- const data = await res.json();
1475
- projectId = data.projectId;
1476
- process.stderr.write(`📦 Project created: ${projectId}\n`);
1477
- } else {
1478
- // Create project with images (URLs and/or local files)
1479
- const base64s = imageFileList.map(imgPath => {
1480
- process.stderr.write(`📤 Uploading ${path.basename(imgPath)}...\n`);
1481
- return readImageAsDataUrl(imgPath);
1482
- });
1483
- if (imageUrlList.length) process.stderr.write(`📤 Attaching ${imageUrlList.length} URL image(s)...\n`);
1484
- const body = {};
1485
- if (base64s.length) body.imageBase64s = base64s;
1486
- if (imageUrlList.length) body.imageUrls = imageUrlList;
1487
- const res = await fetch(`${baseUrl}/api/projects/create`, {
1488
- method: 'POST',
1489
- headers: { 'Content-Type': 'application/json', ...headers },
1490
- body: JSON.stringify(body),
1491
- });
1492
- if (!res.ok) { process.stderr.write(`❌ Failed to create project: ${await res.text()}\n`); process.exit(1); }
1493
- const data = await res.json();
1494
- projectId = data.projectId;
1495
- process.stderr.write(`📦 Project created: ${projectId} (${data.snapshots?.length || 0} images)\n`);
1496
- }
1497
- chatImages.length = 0;
1498
- imageUrlList.length = 0;
1499
- imageFileList.length = 0;
1484
+ // Create an empty project first, then attach media by URL. Local images use
1485
+ // signed upload URLs so the agent never depends on the caller's filesystem.
1486
+ process.stderr.write(`📦 Creating new project...\n`);
1487
+ const res = await fetch(`${baseUrl}/api/projects/create`, {
1488
+ method: 'POST',
1489
+ headers: { 'Content-Type': 'application/json', ...headers },
1490
+ body: JSON.stringify({ title: prompt.slice(0, 50) }),
1491
+ });
1492
+ if (!res.ok) { process.stderr.write(`❌ Failed to create project: ${await res.text()}\n`); process.exit(1); }
1493
+ const data = await res.json();
1494
+ projectId = data.projectId;
1495
+ process.stderr.write(`📦 Project created: ${projectId}\n`);
1500
1496
  }
1501
1497
  // Upload additional images to existing project
1502
1498
  if (imageFileList.length > 0 || imageUrlList.length > 0) {
1503
- const base64s = imageFileList.map(imgPath => {
1504
- process.stderr.write(`📤 Uploading ${path.basename(imgPath)}...\n`);
1505
- return readImageAsDataUrl(imgPath);
1506
- });
1499
+ const uploadedImageUrls = imageFileList.length
1500
+ ? await uploadImageFilesViaSignedUrl(baseUrl, headers, projectId, imageFileList)
1501
+ : [];
1502
+ const allImageUrls = [...uploadedImageUrls, ...imageUrlList];
1507
1503
  if (imageUrlList.length) process.stderr.write(`📤 Attaching ${imageUrlList.length} URL image(s)...\n`);
1508
1504
  const body = { _addToProject: projectId };
1509
- if (base64s.length) body.imageBase64s = base64s;
1510
- if (imageUrlList.length) body.imageUrls = imageUrlList;
1505
+ if (allImageUrls.length) body.imageUrls = allImageUrls;
1511
1506
  const res = await fetch(`${baseUrl}/api/projects/create`, {
1512
1507
  method: 'POST',
1513
1508
  headers: { 'Content-Type': 'application/json', ...headers },
@@ -1515,10 +1510,19 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1515
1510
  });
1516
1511
  if (res.ok) {
1517
1512
  const data = await res.json();
1518
- process.stderr.write(`📤 Added ${data.snapshots?.length || 0} image(s) to project\n`);
1513
+ const addedCount = data.snapshots?.length || 0;
1514
+ if (addedCount < allImageUrls.length) {
1515
+ process.stderr.write(`❌ Added only ${addedCount}/${allImageUrls.length} image(s) to project; aborting run.\n`);
1516
+ process.exit(1);
1517
+ }
1518
+ process.stderr.write(`📤 Added ${addedCount} image(s) to project\n`);
1519
1519
  } else {
1520
- process.stderr.write(`⚠️ Failed to upload images: ${await res.text()}\n`);
1520
+ process.stderr.write(`❌ Failed to add images: ${await res.text()}\n`);
1521
+ process.exit(1);
1521
1522
  }
1523
+ chatImages.length = 0;
1524
+ imageUrlList.length = 0;
1525
+ imageFileList.length = 0;
1522
1526
  }
1523
1527
 
1524
1528
  const resolvedSkill = await resolveChatSkill(baseUrl, headers, activeSkill);
@@ -1816,7 +1820,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1816
1820
  else if (args[i] === '--wait') wait = true;
1817
1821
  }
1818
1822
  if ((!images.length && !video) || !script) {
1819
- console.error('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model seedance-fast|seedance|kling|grok] [--video-resolution auto|480p|720p|1080p|4k] [--keep-original-sound]');
1823
+ console.error('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model seedance-fast|seedance-mini|seedance|kling|grok] [--video-resolution auto|480p|720p|1080p|4k] [--keep-original-sound]');
1820
1824
  process.exit(1);
1821
1825
  }
1822
1826
 
@@ -1835,7 +1839,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1835
1839
  const valid = validateVideoFile(video, {
1836
1840
  maxDuration: MAX_VIDEO_PROVIDER_REFERENCE_DURATION,
1837
1841
  durationTolerance: MAX_VIDEO_PROVIDER_REFERENCE_DURATION_TOLERANCE,
1838
- ...(selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast' ? {
1842
+ ...(selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast' || selectedVideoModel === 'seedance-mini' ? {
1839
1843
  minFramePixels: SEEDANCE_MIN_VIDEO_FRAME_PIXELS,
1840
1844
  minSide: SEEDANCE_MIN_VIDEO_SIDE,
1841
1845
  maxSide: SEEDANCE_MAX_VIDEO_SIDE,
@@ -1853,7 +1857,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1853
1857
  // Standalone MCP tool (no project timeline write)
1854
1858
  process.stderr.write('🎬 Submitting video...\n');
1855
1859
  const vArgs = videoUrl
1856
- ? { videoUrl, editPrompt: script, images, videoModel: selectedVideoModel, videoResolution, referType: (selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast') ? 'feature' : 'base' }
1860
+ ? { videoUrl, editPrompt: script, images, videoModel: selectedVideoModel, videoResolution, referType: (selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast' || selectedVideoModel === 'seedance-mini') ? 'feature' : 'base' }
1857
1861
  : { script, images, videoModel: selectedVideoModel, videoResolution };
1858
1862
  const effectiveDuration = duration || (inputVideoMeta?.duration ? Math.min(MAX_VIDEO_PROVIDER_REFERENCE_DURATION, Math.round(inputVideoMeta.duration)) : undefined);
1859
1863
  if (effectiveDuration) vArgs.duration = effectiveDuration;
@@ -1903,7 +1907,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
1903
1907
  console.log(`Video commands:
1904
1908
  video script --image <file> [--image <file>] "direction" Write video script
1905
1909
  video create --script "..." --image <url> [--duration 10] Submit video task
1906
- video create --script "..." --video <public-url> [--model seedance-fast|seedance|kling] Edit a video (standalone; Grok does not support video refs)
1910
+ video create --script "..." --video <public-url> [--model seedance-fast|seedance-mini|seedance|kling] Edit a video (standalone; Grok does not support video refs)
1907
1911
  video status <taskId> Check video status
1908
1912
  video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
1909
1913
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "Talk to Makaron Agent from the terminal — create projects, edit images, generate videos",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -236,6 +236,7 @@ npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
236
236
 
237
237
  # 3a. Submit image-to-video rendering (images must be public URLs from step 1 or uploaded)
238
238
  npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --model kling
239
+ 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 --model seedance-mini --video-resolution 480p --aspect 9:16
239
240
 
240
241
  # 3b. Edit a video from a local file or public URL
241
242
  npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance-fast
@@ -251,9 +252,9 @@ npx makaron-cli video status <taskId>
251
252
  npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
252
253
  ```
253
254
 
254
- Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--model seedance-fast|seedance|kling|grok`, `--video-resolution auto|480p|720p|1080p|4k`. Default model is `seedance-fast`. SeeDance accepts integer output duration 4-15s (default 5s); Kling supports 5-15s; Grok 1.5 supports 1-15s single-image-to-video only. For `--model grok`, forced `--aspect` is ignored to avoid xAI stretching the source image; pad/create the image at the target shape first or use another model.
255
+ Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration <seconds>`, `--aspect 9:16|16:9|1:1`, `--model seedance-fast|seedance-mini|seedance|kling|grok`, `--video-resolution auto|480p|720p|1080p|4k`. Default model is `seedance-fast`. SeeDance accepts integer output duration 4-15s (default 5s); `seedance-mini` supports 480p/720p and is best for cheaper drafts/multi-size tests; Kling supports 5-15s; Grok 1.5 supports 1-15s single-image-to-video only. For `--model grok`, forced `--aspect` is ignored to avoid xAI stretching the source image; pad/create the image at the target shape first or use another model.
255
256
 
256
- Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance-fast --video` or `--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. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s. Grok does not support video references.
257
+ Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance-fast --video`, `--model seedance-mini --video`, or `--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. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s. Grok does not support video references.
257
258
 
258
259
  ### `music` — Music generation
259
260