makaron-cli 0.13.1 → 0.13.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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +8 -6
- package/bin/makaron.mjs +128 -61
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +8 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.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.13.
|
|
3
|
+
"version": "0.13.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
|
@@ -48,6 +48,12 @@ export MAKARON_API_KEY=mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
|
48
48
|
|
|
49
49
|
Verify: `npx makaron-cli list` should show projects.
|
|
50
50
|
|
|
51
|
+
Check the current credit balance and subscription:
|
|
52
|
+
```bash
|
|
53
|
+
npx makaron-cli credits
|
|
54
|
+
npx makaron-cli credits --json
|
|
55
|
+
```
|
|
56
|
+
|
|
51
57
|
### Let a human claim your account
|
|
52
58
|
|
|
53
59
|
After registering, generate a link for a human to link your API key to their account:
|
|
@@ -90,12 +96,9 @@ npx makaron-cli chat --project <id> --json -b "<prompt>"
|
|
|
90
96
|
# Auto-create project (with or without images)
|
|
91
97
|
npx makaron-cli chat --project auto --image photo.jpg --json -b "make it cinematic"
|
|
92
98
|
npx makaron-cli chat --project auto --image img1.jpg --image img2.jpg --json -b "combine these"
|
|
93
|
-
|
|
94
|
-
# Choose each model role explicitly
|
|
95
|
-
npx makaron-cli chat --project auto --agent-model deepseek-v4-pro --image-model qwen "design a product poster"
|
|
96
99
|
```
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
`chat` always routes agent, image, and video models automatically. Never pass `--agent-model`, `--image-model`, `--video-model`, or the legacy `--model` flag to `chat`; the CLI rejects them before starting a run. Model flags remain available only on explicit low-level commands such as `edit` and `video create`.
|
|
99
102
|
|
|
100
103
|
Returns immediately:
|
|
101
104
|
```json
|
|
@@ -112,7 +115,7 @@ Returns immediately:
|
|
|
112
115
|
| Fix one moment in a video from a screenshot | `npx makaron-cli chat --project <id> --image screenshot.png "@4 this frame should be Paris; only fix this moment"` |
|
|
113
116
|
| Cut or assemble video | `npx makaron-cli chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"` |
|
|
114
117
|
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
115
|
-
| Beat-sync video from audio | `npx makaron-cli chat --project auto --audio beat.mp3 --video-
|
|
118
|
+
| Beat-sync video from audio | `npx makaron-cli chat --project auto --audio beat.mp3 --video-resolution 480p "make a beat-synced video"` |
|
|
116
119
|
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
117
120
|
|
|
118
121
|
### Marketplace skills
|
|
@@ -213,7 +216,6 @@ Attach a short song, beat, or voice recording when the video should follow audio
|
|
|
213
216
|
```bash
|
|
214
217
|
npx makaron-cli chat --project auto \
|
|
215
218
|
--audio beat.mp3 \
|
|
216
|
-
--video-model seedance-fast \
|
|
217
219
|
--video-resolution 480p \
|
|
218
220
|
-b "make a 15s beat-synced video"
|
|
219
221
|
```
|
package/bin/makaron.mjs
CHANGED
|
@@ -27,7 +27,7 @@ const APP_URL = process.env.MAKARON_APP_URL || DEFAULT_URL;
|
|
|
27
27
|
const NPM_PACKAGE_NAME = 'makaron-cli';
|
|
28
28
|
const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
29
29
|
const UPDATE_CHECK_TIMEOUT_MS = 400;
|
|
30
|
-
const
|
|
30
|
+
const AGENT_WAIT_TIMEOUT_SECONDS = Math.max(900, Number(process.env.MAKARON_AGENT_WAIT_TIMEOUT_SECONDS || 10_800));
|
|
31
31
|
|
|
32
32
|
// Public anon key (safe to embed — only enables auth, not data access)
|
|
33
33
|
const SUPABASE_URL = 'https://sdyrtztrjgmmpnirswxt.supabase.co';
|
|
@@ -55,14 +55,6 @@ function warnLegacyModelFlag(replacement) {
|
|
|
55
55
|
process.stderr.write(`⚠️ --model is deprecated here; use ${replacement}.\n`);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
function validateAgentModel(value) {
|
|
59
|
-
if (!AGENT_MODELS.includes(value)) {
|
|
60
|
-
process.stderr.write(`❌ Unknown agent model: ${value}\nChoose one of: ${AGENT_MODELS.join(', ')}\n`);
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
return value;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
58
|
function getCliVersion() {
|
|
67
59
|
try {
|
|
68
60
|
const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
|
|
@@ -290,15 +282,15 @@ Options:
|
|
|
290
282
|
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
291
283
|
--audio <file|url> Attach a song, beat, or voice reference. MP3/WAV, repeatable.
|
|
292
284
|
--skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
|
|
293
|
-
--image-model <name> Image model: gemini, gemini-lite, qwen, openai, pony, or wai.
|
|
294
|
-
--video-model <name> Preferred video model: seedance-fast, seedance-mini, seedance, kling, grok, or google-omni.
|
|
295
|
-
--agent-model <name> Agent model: auto, gpt-5.6-terra, gpt-5.6-sol, gpt-5.6-luna, grok-4.5, or deepseek-v4-pro.
|
|
296
285
|
--video-resolution <res> Video resolution: auto, 480p, 720p, 1080p, or 4k.
|
|
297
286
|
--background, -b Submit and print a runId.
|
|
298
287
|
--json Output structured JSON.
|
|
299
288
|
--stream Legacy live SSE stream.
|
|
300
289
|
--help, -h Show this help.
|
|
301
290
|
|
|
291
|
+
Model routing is automatic in chat. Do not pass --agent-model, --image-model,
|
|
292
|
+
--video-model, or the legacy --model flag.
|
|
293
|
+
|
|
302
294
|
What you can ask:
|
|
303
295
|
Image edit
|
|
304
296
|
makaron chat --project <id> --image photo.jpg "remove the person in the background"
|
|
@@ -322,7 +314,7 @@ What you can ask:
|
|
|
322
314
|
makaron chat --project <id> "add calm piano background music"
|
|
323
315
|
|
|
324
316
|
Reference audio / beat sync
|
|
325
|
-
makaron chat --project auto --audio beat.mp3 --video-
|
|
317
|
+
makaron chat --project auto --audio beat.mp3 --video-resolution 480p "用这个音乐做卡点视频"
|
|
326
318
|
makaron chat --project <id> --audio https://example.com/beat.mp3 "add this as the soundtrack"
|
|
327
319
|
|
|
328
320
|
Motion design
|
|
@@ -359,10 +351,9 @@ async function streamAgent(baseUrl, headers, projectId, prompt, opts = {}) {
|
|
|
359
351
|
projectId,
|
|
360
352
|
prompt,
|
|
361
353
|
headless: true,
|
|
362
|
-
...(opts.preferredModel ? { preferredModel: opts.preferredModel } : {}),
|
|
363
|
-
...(opts.videoModel ? { videoModel: opts.videoModel } : {}),
|
|
364
354
|
...(opts.videoResolution ? { videoResolution: opts.videoResolution } : {}),
|
|
365
|
-
...(opts.
|
|
355
|
+
...(opts.uploadedVideoCount ? { uploadedVideoCount: opts.uploadedVideoCount } : {}),
|
|
356
|
+
...(opts.turnMediaCount ? { turnMediaCount: opts.turnMediaCount } : {}),
|
|
366
357
|
}),
|
|
367
358
|
signal: controller.signal,
|
|
368
359
|
});
|
|
@@ -469,13 +460,12 @@ async function streamAgent(baseUrl, headers, projectId, prompt, opts = {}) {
|
|
|
469
460
|
|
|
470
461
|
async function submitRun(baseUrl, headers, projectId, prompt, opts = {}) {
|
|
471
462
|
const body = { projectId, prompt };
|
|
472
|
-
if (opts.preferredModel) body.preferredModel = opts.preferredModel;
|
|
473
|
-
if (opts.agentModel && opts.agentModel !== 'auto') body.agentModel = opts.agentModel;
|
|
474
|
-
if (opts.videoModel) body.videoModel = opts.videoModel;
|
|
475
463
|
if (opts.videoResolution) body.videoResolution = opts.videoResolution;
|
|
476
464
|
if (opts.currentSnapshotIndex != null) body.currentSnapshotIndex = opts.currentSnapshotIndex;
|
|
477
465
|
if (opts.isNsfw) body.isNsfw = opts.isNsfw;
|
|
478
466
|
if (opts.audioAttachments?.length) body.audioAttachments = opts.audioAttachments;
|
|
467
|
+
if (opts.uploadedVideoCount) body.uploadedVideoCount = opts.uploadedVideoCount;
|
|
468
|
+
if (opts.turnMediaCount) body.turnMediaCount = opts.turnMediaCount;
|
|
479
469
|
|
|
480
470
|
const res = await fetch(`${baseUrl}/api/agent/run`, {
|
|
481
471
|
method: 'POST',
|
|
@@ -519,7 +509,7 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
519
509
|
try {
|
|
520
510
|
const res = await fetch(`${baseUrl}/api/agent/run/${runId}?${params}`, { headers });
|
|
521
511
|
if (!res.ok) {
|
|
522
|
-
if (elapsed >
|
|
512
|
+
if (elapsed > AGENT_WAIT_TIMEOUT_SECONDS) { process.stderr.write(`\n❌ Timeout after ${elapsed}s\n`); process.exit(1); }
|
|
523
513
|
continue;
|
|
524
514
|
}
|
|
525
515
|
data = await res.json();
|
|
@@ -569,6 +559,13 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
569
559
|
case 'music_task':
|
|
570
560
|
process.stderr.write(`\n🎵 Music submitted: ${ev.data?.taskId}\n`);
|
|
571
561
|
break;
|
|
562
|
+
case 'studio_run': {
|
|
563
|
+
const stage = ev.data?.currentStage || ev.data?.current_stage || 'complete';
|
|
564
|
+
const recipe = ev.data?.recipe || 'studio';
|
|
565
|
+
const status = ev.data?.status || 'running';
|
|
566
|
+
process.stderr.write(`\nStudio Run: ${recipe} / ${stage} / ${status}\n`);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
572
569
|
case 'error':
|
|
573
570
|
process.stderr.write(`\n❌ Error: ${ev.data?.message}\n`);
|
|
574
571
|
break;
|
|
@@ -580,6 +577,7 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
580
577
|
|
|
581
578
|
// Check terminal status
|
|
582
579
|
if (data.status === 'completed' || data.status === 'failed' || data.status === 'aborted') {
|
|
580
|
+
normalizeRunResponse(data);
|
|
583
581
|
if (printedText && !json) process.stdout.write('\n');
|
|
584
582
|
if (data.status === 'completed' && exportCompositions) {
|
|
585
583
|
data = await exportAnimatedCompositionsFromRun(baseUrl, headers, data, {
|
|
@@ -611,7 +609,7 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
611
609
|
process.stderr.write(`🔗 ${APP_URL}/projects/${data.projectId}\n`);
|
|
612
610
|
}
|
|
613
611
|
|
|
614
|
-
if (data.status === 'failed') process.exit(1);
|
|
612
|
+
if (data.status === 'failed' || data.status === 'aborted') process.exit(1);
|
|
615
613
|
return data;
|
|
616
614
|
}
|
|
617
615
|
}
|
|
@@ -620,11 +618,15 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
620
618
|
// ─── Pick Helper ────────────────────────────────────────────────────────────
|
|
621
619
|
|
|
622
620
|
function applyPick(data, field) {
|
|
621
|
+
const videoUrls = [...new Set([
|
|
622
|
+
...(data.output || []).filter(o => o.type === 'video' && o.url).map(o => o.url),
|
|
623
|
+
...(data.result?.videos || []).filter(v => v.videoUrl).map(v => v.videoUrl),
|
|
624
|
+
])];
|
|
623
625
|
switch (field) {
|
|
624
626
|
case 'first_image_url': return data.output?.find(o => o.type === 'image')?.url || null;
|
|
625
627
|
case 'image_urls': return (data.output || []).filter(o => o.type === 'image' && o.url).map(o => o.url);
|
|
626
|
-
case 'first_video_url': return
|
|
627
|
-
case 'video_urls': return
|
|
628
|
+
case 'first_video_url': return videoUrls[0] || null;
|
|
629
|
+
case 'video_urls': return videoUrls;
|
|
628
630
|
case 'first_design_url': return data.output?.find(o => o.type === 'design')?.url || null;
|
|
629
631
|
case 'design_urls': return (data.output || []).filter(o => o.type === 'design' && o.url).map(o => o.url);
|
|
630
632
|
case 'first_music_url': return data.output?.find(o => o.type === 'music' && o.url)?.url || null;
|
|
@@ -635,6 +637,8 @@ function applyPick(data, field) {
|
|
|
635
637
|
description: action.description,
|
|
636
638
|
source: action.source,
|
|
637
639
|
}));
|
|
640
|
+
case 'studio_run': return [...(data.output || [])].reverse().find(o => o.type === 'studio_run') || null;
|
|
641
|
+
case 'studio_recipe': return [...(data.output || [])].reverse().find(o => o.type === 'studio_run')?.recipe || null;
|
|
638
642
|
case 'project_url': return data.project_url || data.projectUrl || null;
|
|
639
643
|
case 'output': return data.output || [];
|
|
640
644
|
case 'text': return data.output?.find(o => o.type === 'text')?.content || null;
|
|
@@ -656,7 +660,7 @@ async function watchRun(baseUrl, headers, runId, opts = {}) {
|
|
|
656
660
|
try {
|
|
657
661
|
const res = await fetch(`${baseUrl}/api/agent/run/${runId}`, { headers });
|
|
658
662
|
if (!res.ok) {
|
|
659
|
-
if (elapsed >
|
|
663
|
+
if (elapsed > AGENT_WAIT_TIMEOUT_SECONDS) { process.stderr.write(`Timeout after ${elapsed}s\n`); process.exit(2); }
|
|
660
664
|
await new Promise(r => setTimeout(r, interval));
|
|
661
665
|
continue;
|
|
662
666
|
}
|
|
@@ -1042,6 +1046,33 @@ async function fetchMarketplaceSkills(baseUrl, opts = {}) {
|
|
|
1042
1046
|
return skills.map(normalizeMarketplaceSkill);
|
|
1043
1047
|
}
|
|
1044
1048
|
|
|
1049
|
+
async function fetchBuiltInSkills(baseUrl) {
|
|
1050
|
+
const res = await fetch(`${baseUrl}/api/skills?include=internal`);
|
|
1051
|
+
if (!res.ok) {
|
|
1052
|
+
process.stderr.write(`Error ${res.status}: ${await res.text()}\n`);
|
|
1053
|
+
process.exit(1);
|
|
1054
|
+
}
|
|
1055
|
+
const data = await res.json();
|
|
1056
|
+
return (data.skills || []).filter(skill => skill.builtIn);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function printBuiltInSkills(skills) {
|
|
1060
|
+
if (!skills.length) {
|
|
1061
|
+
console.log('No built-in skills found.');
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
console.log(`Built-in skills: ${skills.length}\n`);
|
|
1065
|
+
for (const skill of skills) {
|
|
1066
|
+
const recipe = skill.studioRunRecipe ? ` [Studio Run: ${skill.studioRunRecipe}]` : '';
|
|
1067
|
+
const source = skill.sourceMediaRequired ? ' [source media required]' : '';
|
|
1068
|
+
const adapter = skill.sourceProject === 'openmontage'
|
|
1069
|
+
? ` [OpenMontage: ${skill.supportLevel || 'adapted'}${skill.canonicalSkill && skill.canonicalSkill !== skill.name ? ` -> ${skill.canonicalSkill}` : ''}]`
|
|
1070
|
+
: '';
|
|
1071
|
+
console.log(` ${skill.name}${recipe}${source}${adapter}`);
|
|
1072
|
+
if (skill.description) console.log(` ${String(skill.description).replace(/\s+/g, ' ').trim()}`);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1045
1076
|
function marketplaceSearchText(skill) {
|
|
1046
1077
|
const localized = [...localizedValues(skill.labels), ...localizedValues(skill.prompts)];
|
|
1047
1078
|
return [
|
|
@@ -1554,6 +1585,7 @@ Commands:
|
|
|
1554
1585
|
register --verify --challenge-id <id> --answer <n> Verify and save API key
|
|
1555
1586
|
claim Get claim URL for human to link account
|
|
1556
1587
|
login Log in to Makaron (human interactive)
|
|
1588
|
+
credits Show current credit balance
|
|
1557
1589
|
list (ls) List all projects
|
|
1558
1590
|
project media <projectId> --json List timeline media for a project
|
|
1559
1591
|
create --image <file> Create project from local image
|
|
@@ -1561,7 +1593,7 @@ Commands:
|
|
|
1561
1593
|
create --title "name" Create empty project (text-to-image)
|
|
1562
1594
|
|
|
1563
1595
|
chat --project <id> "message" Chat (non-blocking, polls for result)
|
|
1564
|
-
chat --project <id> --skill <id> Use
|
|
1596
|
+
chat --project <id> --skill <id> Use a built-in or marketplace skill
|
|
1565
1597
|
chat --project <id> --video <file> Attach video to conversation
|
|
1566
1598
|
chat --project <id> --audio <file> Attach song/beat/voice reference
|
|
1567
1599
|
chat --project <id> -b "message" Background: submit and print runId
|
|
@@ -1578,7 +1610,7 @@ Commands:
|
|
|
1578
1610
|
Export editable Remotion composition to MP4
|
|
1579
1611
|
responses list --project <id> List runs for a project
|
|
1580
1612
|
abort <runId> Abort a running Agent
|
|
1581
|
-
skills list|search|show|install Browse and
|
|
1613
|
+
skills list|search|show|install Browse built-in and marketplace skills
|
|
1582
1614
|
|
|
1583
1615
|
edit [--image <file>] "prompt" AI image edit / text-to-image
|
|
1584
1616
|
analyze --video <file|url> Analyze video content
|
|
@@ -1587,26 +1619,17 @@ Commands:
|
|
|
1587
1619
|
|
|
1588
1620
|
admin Admin commands (skills, upload, set-admin)
|
|
1589
1621
|
|
|
1590
|
-
Model selection:
|
|
1591
|
-
--agent-model <name> Reasoning/tool model: auto, gpt-5.6-terra, gpt-5.6-sol,
|
|
1592
|
-
gpt-5.6-luna, grok-4.5, or deepseek-v4-pro
|
|
1593
|
-
--image-model <name> Image model: gemini, gemini-lite, qwen, openai,
|
|
1594
|
-
pony, or wai
|
|
1595
|
-
--video-model <name> Video model: seedance-fast, seedance-mini, seedance,
|
|
1596
|
-
kling, grok, or google-omni
|
|
1597
|
-
|
|
1598
1622
|
Examples:
|
|
1599
|
-
makaron chat --project auto
|
|
1600
|
-
makaron chat --project <id>
|
|
1601
|
-
makaron chat --project <id>
|
|
1623
|
+
makaron chat --project auto "plan a launch poster"
|
|
1624
|
+
makaron chat --project <id> "make it cinematic"
|
|
1625
|
+
makaron chat --project <id> "turn this into a short video"
|
|
1602
1626
|
|
|
1603
1627
|
Run makaron <command> --help for command-specific options.
|
|
1604
|
-
|
|
1628
|
+
Chat chooses agent, image, and video models automatically.
|
|
1605
1629
|
|
|
1606
1630
|
Environment:
|
|
1607
1631
|
MAKARON_API_KEY API key (mk_live_xxx) — recommended for agents
|
|
1608
1632
|
MAKARON_URL API base (default: ${DEFAULT_URL})
|
|
1609
|
-
MAKARON_AGENT_MODEL Default Agent model; --agent-model takes precedence
|
|
1610
1633
|
`);
|
|
1611
1634
|
}
|
|
1612
1635
|
|
|
@@ -1677,6 +1700,8 @@ function printHelp(topic, subtopic) {
|
|
|
1677
1700
|
`);
|
|
1678
1701
|
} else if (topic === 'list' || topic === 'ls') {
|
|
1679
1702
|
console.log('Usage: makaron list');
|
|
1703
|
+
} else if (topic === 'credits' || topic === 'credit' || topic === 'balance') {
|
|
1704
|
+
console.log('Usage: makaron credits [--json]');
|
|
1680
1705
|
} else if (topic === 'project' || topic === 'projects') {
|
|
1681
1706
|
if (subtopic === 'media') console.log('Usage: makaron project media <projectId> [--json]');
|
|
1682
1707
|
else console.log(`Project commands:
|
|
@@ -1689,13 +1714,15 @@ function printHelp(topic, subtopic) {
|
|
|
1689
1714
|
} else if (topic === 'install-skill') {
|
|
1690
1715
|
console.log('Usage: makaron install-skill [--global] [--agent <agent>] [--yes]');
|
|
1691
1716
|
} else if (topic === 'skills') {
|
|
1692
|
-
if (subtopic === 'list') console.log('Usage: makaron skills list [--json]');
|
|
1717
|
+
if (subtopic === 'list') console.log('Usage: makaron skills list [--built-in] [--json]');
|
|
1693
1718
|
else if (subtopic === 'search') console.log('Usage: makaron skills search <query> [--json]');
|
|
1694
1719
|
else if (subtopic === 'show') console.log('Usage: makaron skills show <marketplace-id|label> [--json]');
|
|
1695
1720
|
else if (subtopic === 'install') console.log('Usage: makaron skills install <marketplace-id|label> [--json]');
|
|
1696
|
-
else console.log(`Skill
|
|
1721
|
+
else console.log(`Skill commands:
|
|
1722
|
+
skills list --built-in List all built-in Makaron skills and Studio Run recipes
|
|
1697
1723
|
skills list List marketplace skills
|
|
1698
1724
|
skills search <query> Search marketplace skills
|
|
1725
|
+
skills show <id|label> --built-in Show a built-in skill
|
|
1699
1726
|
skills show <id|label> Show a marketplace skill
|
|
1700
1727
|
skills install <id|label> Install a marketplace skill to your workspace
|
|
1701
1728
|
|
|
@@ -1783,6 +1810,29 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1783
1810
|
installAgentSkill(args.slice(1));
|
|
1784
1811
|
} else if (command === 'login') {
|
|
1785
1812
|
await login();
|
|
1813
|
+
} else if (command === 'credits' || command === 'credit' || command === 'balance') {
|
|
1814
|
+
const { headers, baseUrl } = getAuth();
|
|
1815
|
+
const res = await fetch(`${baseUrl}/api/billing/credits`, { headers });
|
|
1816
|
+
const data = await res.json().catch(() => null);
|
|
1817
|
+
if (!res.ok || !data) {
|
|
1818
|
+
const message = data?.error || data?.message || (res.ok ? 'Invalid response' : `HTTP ${res.status}`);
|
|
1819
|
+
process.stderr.write(`Failed to get credits: ${message}\n`);
|
|
1820
|
+
process.exit(1);
|
|
1821
|
+
}
|
|
1822
|
+
if (args.includes('--json')) {
|
|
1823
|
+
console.log(JSON.stringify(data));
|
|
1824
|
+
} else {
|
|
1825
|
+
console.log(`Credits: ${data.balance ?? 0}`);
|
|
1826
|
+
console.log(`Lifetime purchased: ${data.lifetimePurchased ?? 0}`);
|
|
1827
|
+
console.log(`Lifetime used: ${data.lifetimeUsed ?? 0}`);
|
|
1828
|
+
if (data.subscription) {
|
|
1829
|
+
const plan = data.subscription.planId || 'unknown';
|
|
1830
|
+
const status = data.subscription.status ? ` (${data.subscription.status})` : '';
|
|
1831
|
+
console.log(`Subscription: ${plan}${status}`);
|
|
1832
|
+
} else {
|
|
1833
|
+
console.log('Subscription: none');
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1786
1836
|
} else if (command === 'create') {
|
|
1787
1837
|
const { headers, baseUrl } = getAuth();
|
|
1788
1838
|
const opts = { images: [], imageUrls: [] };
|
|
@@ -1812,10 +1862,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1812
1862
|
let background = false;
|
|
1813
1863
|
let jsonOutput = false;
|
|
1814
1864
|
let activeSkill = undefined;
|
|
1815
|
-
let videoModel = undefined;
|
|
1816
1865
|
let videoResolution = undefined;
|
|
1817
|
-
let preferredModel = undefined;
|
|
1818
|
-
let agentModel = process.env.MAKARON_AGENT_MODEL || 'auto';
|
|
1819
1866
|
for (let i = 1; i < args.length; i++) {
|
|
1820
1867
|
if (args[i] === '--project' && args[i + 1]) projectId = args[++i];
|
|
1821
1868
|
else if (args[i] === '--image' && args[i + 1]) chatImages.push(args[++i]);
|
|
@@ -1826,13 +1873,14 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1826
1873
|
else if (args[i] === '--stream') useStream = true;
|
|
1827
1874
|
else if (args[i] === '--background' || args[i] === '-b') background = true;
|
|
1828
1875
|
else if (args[i] === '--json') jsonOutput = true;
|
|
1829
|
-
else if (args[i] === '--video-model' && args[i + 1]) videoModel = args[++i];
|
|
1830
1876
|
else if (args[i] === '--video-resolution' && args[i + 1]) videoResolution = args[++i];
|
|
1831
|
-
else if (
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1877
|
+
else if (
|
|
1878
|
+
['--agent-model', '--image-model', '--video-model', '--model'].includes(args[i])
|
|
1879
|
+
|| ['--agent-model=', '--image-model=', '--video-model=', '--model='].some(prefix => args[i].startsWith(prefix))
|
|
1880
|
+
) {
|
|
1881
|
+
const flag = args[i].split('=')[0];
|
|
1882
|
+
process.stderr.write(`❌ makaron chat chooses agent, image, and video models automatically. Remove ${flag} and retry.\n`);
|
|
1883
|
+
process.exit(1);
|
|
1836
1884
|
}
|
|
1837
1885
|
else promptParts.push(args[i]);
|
|
1838
1886
|
}
|
|
@@ -1842,7 +1890,6 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1842
1890
|
console.error('Run: makaron chat --help');
|
|
1843
1891
|
process.exit(1);
|
|
1844
1892
|
}
|
|
1845
|
-
agentModel = validateAgentModel(agentModel);
|
|
1846
1893
|
const { headers, baseUrl } = getAuth();
|
|
1847
1894
|
// Split images into URLs vs local files
|
|
1848
1895
|
const imageUrlList = chatImages.filter(p => p.startsWith('http://') || p.startsWith('https://'));
|
|
@@ -1888,6 +1935,9 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1888
1935
|
process.exit(1);
|
|
1889
1936
|
}
|
|
1890
1937
|
|
|
1938
|
+
let uploadedTurnMediaCount = 0;
|
|
1939
|
+
let uploadedTurnVideoCount = 0;
|
|
1940
|
+
|
|
1891
1941
|
// --project auto: create a new project (with images/videos if provided)
|
|
1892
1942
|
if (!projectId || projectId === 'auto') {
|
|
1893
1943
|
// Create an empty project first, then attach media by URL. Local images use
|
|
@@ -1925,6 +1975,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1925
1975
|
process.exit(1);
|
|
1926
1976
|
}
|
|
1927
1977
|
process.stderr.write(`📤 Added ${addedCount} image(s) to project\n`);
|
|
1978
|
+
uploadedTurnMediaCount += addedCount;
|
|
1928
1979
|
} else {
|
|
1929
1980
|
process.stderr.write(`❌ Failed to add images: ${await res.text()}\n`);
|
|
1930
1981
|
process.exit(1);
|
|
@@ -2016,19 +2067,22 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2016
2067
|
const data = await res.json();
|
|
2017
2068
|
const videoSnaps = (data.snapshots || []).filter(s => s.type === 'video');
|
|
2018
2069
|
process.stderr.write(`📹 Added ${videoSnaps.length} video(s) to timeline\n`);
|
|
2070
|
+
uploadedTurnVideoCount += videoSnaps.length;
|
|
2071
|
+
uploadedTurnMediaCount += videoSnaps.length;
|
|
2019
2072
|
} else {
|
|
2020
2073
|
process.stderr.write(`⚠️ Failed to add videos: ${await res.text()}\n`);
|
|
2021
2074
|
}
|
|
2022
2075
|
}
|
|
2023
2076
|
|
|
2024
|
-
// Inject hint so Agent knows videos are available
|
|
2025
|
-
const hint = `[User uploaded ${chatVideos.length === 1 ? 'a video' : `${chatVideos.length} videos`}. Use analyze_video to understand the content.]`;
|
|
2026
|
-
finalPrompt = `${finalPrompt}\n\n${hint}`;
|
|
2027
2077
|
}
|
|
2028
2078
|
|
|
2029
2079
|
if (useStream) {
|
|
2030
2080
|
// Legacy SSE mode
|
|
2031
|
-
const { results } = await streamAgent(baseUrl, headers, projectId, finalPrompt, {
|
|
2081
|
+
const { results } = await streamAgent(baseUrl, headers, projectId, finalPrompt, {
|
|
2082
|
+
videoResolution,
|
|
2083
|
+
uploadedVideoCount: uploadedTurnVideoCount,
|
|
2084
|
+
turnMediaCount: uploadedTurnMediaCount,
|
|
2085
|
+
});
|
|
2032
2086
|
process.stderr.write('\n━━━ Results ━━━\n');
|
|
2033
2087
|
for (const img of results.images) process.stderr.write(`🖼️ Image: ${img.imageUrl}\n`);
|
|
2034
2088
|
for (const d of results.designs) process.stderr.write(`🎨 ${d.desc}\n`);
|
|
@@ -2037,7 +2091,12 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2037
2091
|
for (const task of results.musicTasks) await pollMusic(baseUrl, headers, task.taskId);
|
|
2038
2092
|
} else {
|
|
2039
2093
|
// Default: fire-and-forget + poll
|
|
2040
|
-
const { runId } = await submitRun(baseUrl, headers, projectId, finalPrompt, {
|
|
2094
|
+
const { runId } = await submitRun(baseUrl, headers, projectId, finalPrompt, {
|
|
2095
|
+
videoResolution,
|
|
2096
|
+
audioAttachments,
|
|
2097
|
+
uploadedVideoCount: uploadedTurnVideoCount,
|
|
2098
|
+
turnMediaCount: uploadedTurnMediaCount,
|
|
2099
|
+
});
|
|
2041
2100
|
if (background) {
|
|
2042
2101
|
// Just print runId and exit
|
|
2043
2102
|
if (jsonOutput) {
|
|
@@ -2225,8 +2284,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2225
2284
|
const jsonOutput = args.includes('--json');
|
|
2226
2285
|
|
|
2227
2286
|
if (sub === 'list') {
|
|
2228
|
-
const
|
|
2287
|
+
const builtIn = args.includes('--built-in');
|
|
2288
|
+
const skills = builtIn ? await fetchBuiltInSkills(baseUrl) : await fetchMarketplaceSkills(baseUrl);
|
|
2229
2289
|
if (jsonOutput) console.log(JSON.stringify({ skills }, null, 2));
|
|
2290
|
+
else if (builtIn) printBuiltInSkills(skills);
|
|
2230
2291
|
else printMarketplaceSkills(skills);
|
|
2231
2292
|
} else if (sub === 'search') {
|
|
2232
2293
|
const query = args.filter((arg, index) => index > 1 && arg !== '--json').join(' ').trim();
|
|
@@ -2243,11 +2304,15 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2243
2304
|
else printMarketplaceSkills(skills);
|
|
2244
2305
|
} else if (sub === 'show') {
|
|
2245
2306
|
const identifier = args[2];
|
|
2246
|
-
if (!identifier) { console.error('Usage: makaron skills show <
|
|
2247
|
-
const
|
|
2248
|
-
const
|
|
2307
|
+
if (!identifier) { console.error('Usage: makaron skills show <id|label> [--built-in] [--json]'); process.exit(1); }
|
|
2308
|
+
const builtIn = args.includes('--built-in');
|
|
2309
|
+
const skills = builtIn ? await fetchBuiltInSkills(baseUrl) : await fetchMarketplaceSkills(baseUrl);
|
|
2310
|
+
const skill = builtIn
|
|
2311
|
+
? skills.find(candidate => candidate.name === identifier || candidate.label?.toLowerCase() === identifier.toLowerCase())
|
|
2312
|
+
: findMarketplaceSkill(skills, identifier);
|
|
2249
2313
|
if (!skill) { console.error(`Skill not found: ${identifier}`); process.exit(1); }
|
|
2250
2314
|
if (jsonOutput) console.log(JSON.stringify(skill, null, 2));
|
|
2315
|
+
else if (builtIn) printBuiltInSkills([skill]);
|
|
2251
2316
|
else printMarketplaceSkill(skill);
|
|
2252
2317
|
} else if (sub === 'install') {
|
|
2253
2318
|
const identifier = args[2];
|
|
@@ -2260,9 +2325,11 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
2260
2325
|
if (jsonOutput) console.log(JSON.stringify({ ...data, marketplaceId: skill.id, label: skill.label }, null, 2));
|
|
2261
2326
|
else console.log(data.skillName);
|
|
2262
2327
|
} else {
|
|
2263
|
-
console.log(`Skill
|
|
2328
|
+
console.log(`Skill commands:
|
|
2329
|
+
skills list --built-in List all built-in Makaron skills and Studio Run recipes
|
|
2264
2330
|
skills list List marketplace skills
|
|
2265
2331
|
skills search <query> Search marketplace skills
|
|
2332
|
+
skills show <id|label> --built-in Show a built-in skill
|
|
2266
2333
|
skills show <id|label> Show a marketplace skill
|
|
2267
2334
|
skills install <id|label> Install a marketplace skill to your workspace
|
|
2268
2335
|
`);
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -44,6 +44,12 @@ export MAKARON_API_KEY=mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
|
44
44
|
|
|
45
45
|
Verify: `npx makaron-cli list` should show projects.
|
|
46
46
|
|
|
47
|
+
Check the current credit balance and subscription:
|
|
48
|
+
```bash
|
|
49
|
+
npx makaron-cli credits
|
|
50
|
+
npx makaron-cli credits --json
|
|
51
|
+
```
|
|
52
|
+
|
|
47
53
|
## Core Workflow
|
|
48
54
|
|
|
49
55
|
```bash
|
|
@@ -77,12 +83,9 @@ npx makaron-cli chat --project <id> --json -b "<prompt>"
|
|
|
77
83
|
# Auto-create project (with or without images)
|
|
78
84
|
npx makaron-cli chat --project auto --image photo.jpg --json -b "make it cinematic"
|
|
79
85
|
npx makaron-cli chat --project auto --image img1.jpg --image img2.jpg --json -b "combine these"
|
|
80
|
-
|
|
81
|
-
# Choose each model role explicitly
|
|
82
|
-
npx makaron-cli chat --project auto --agent-model deepseek-v4-pro --image-model qwen "design a product poster"
|
|
83
86
|
```
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
`chat` always routes agent, image, and video models automatically. Never pass `--agent-model`, `--image-model`, `--video-model`, or the legacy `--model` flag to `chat`; the CLI rejects them before starting a run. Model flags remain available only on explicit low-level commands such as `edit` and `video create`.
|
|
86
89
|
|
|
87
90
|
Returns immediately:
|
|
88
91
|
```json
|
|
@@ -99,7 +102,7 @@ Returns immediately:
|
|
|
99
102
|
| Fix one moment in a video from a screenshot | `npx makaron-cli chat --project <id> --image screenshot.png "@4 this frame should be Paris; only fix this moment"` |
|
|
100
103
|
| Cut or assemble video | `npx makaron-cli chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"` |
|
|
101
104
|
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
102
|
-
| Beat-sync video from audio | `npx makaron-cli chat --project auto --audio beat.mp3 --video-
|
|
105
|
+
| Beat-sync video from audio | `npx makaron-cli chat --project auto --audio beat.mp3 --video-resolution 480p "make a beat-synced video"` |
|
|
103
106
|
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
104
107
|
|
|
105
108
|
### Marketplace skills
|
|
@@ -173,7 +176,6 @@ Attach a short song, beat, or voice recording when the video should follow audio
|
|
|
173
176
|
```bash
|
|
174
177
|
npx makaron-cli chat --project auto \
|
|
175
178
|
--audio beat.mp3 \
|
|
176
|
-
--video-model seedance-fast \
|
|
177
179
|
--video-resolution 480p \
|
|
178
180
|
-b "make a 15s beat-synced video"
|
|
179
181
|
```
|