makaron-cli 0.8.4 → 0.9.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 +41 -4
- package/bin/makaron.mjs +177 -5
- package/package.json +1 -2
- package/skills/makaron/SKILL.md +41 -5
- package/SKILL.md +0 -311
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "AI image editing, video generation, and music creation via CLI. Agents can self-register, 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
|
@@ -75,6 +75,10 @@ npx makaron-cli responses get $RUN_ID --wait --json
|
|
|
75
75
|
|
|
76
76
|
Use `chat` for all creative tasks. Makaron Agent decides how to execute — it can edit images, generate videos, compose music, and create designs in a single conversation.
|
|
77
77
|
|
|
78
|
+
```bash
|
|
79
|
+
npx makaron-cli chat --help
|
|
80
|
+
```
|
|
81
|
+
|
|
78
82
|
### Submit a request
|
|
79
83
|
|
|
80
84
|
```bash
|
|
@@ -91,6 +95,18 @@ Returns immediately:
|
|
|
91
95
|
{"runId": "xxx", "projectId": "...", "projectUrl": "https://www.makaron.app/projects/...", "status": "running"}
|
|
92
96
|
```
|
|
93
97
|
|
|
98
|
+
### Common workflows
|
|
99
|
+
|
|
100
|
+
| What you want | Example |
|
|
101
|
+
|--------------|---------|
|
|
102
|
+
| Edit an image | `npx makaron-cli chat --project <id> --image photo.jpg "remove the person in the background"` |
|
|
103
|
+
| Generate an image | `npx makaron-cli chat --project auto "generate a cinematic poster of a rainy Tokyo alley"` |
|
|
104
|
+
| Make a video from the current project | `npx makaron-cli chat --project <id> "make this into a 5 second cinematic video"` |
|
|
105
|
+
| 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"` |
|
|
106
|
+
| Cut or assemble video | `npx makaron-cli chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"` |
|
|
107
|
+
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
108
|
+
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
109
|
+
|
|
94
110
|
### With additional images (existing project)
|
|
95
111
|
|
|
96
112
|
```bash
|
|
@@ -124,6 +140,18 @@ Video files are uploaded via signed URL. CLI local video uploads support `.mp4`,
|
|
|
124
140
|
The agent understands video content natively — it can analyze scenes, edit, extend, and compose videos. Seedance video-reference editing is still limited to ~15s provider references, so longer uploaded videos should be split/prepared by the agent before model submission; Kling remains the base/direct edit path.
|
|
125
141
|
Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct `video create` is standalone and does not write timeline entries.
|
|
126
142
|
|
|
143
|
+
### Fix one video moment from a screenshot
|
|
144
|
+
|
|
145
|
+
When a video is mostly good but one moment needs a local fix, attach a screenshot of the problem frame and describe the correction in normal language:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx makaron-cli chat --project <id> \
|
|
149
|
+
--image screenshot.png \
|
|
150
|
+
"@4 this frame should be Paris, keep the same style and only fix this moment"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Makaron can locate the screenshot in the video, regenerate only the nearby segment, and then print a `Next steps` command when the new clip should be stitched back into the full MP4.
|
|
154
|
+
|
|
127
155
|
### Check status (single query)
|
|
128
156
|
|
|
129
157
|
```bash
|
|
@@ -170,15 +198,14 @@ npx makaron-cli edit --image photo.jpg "add cinematic warm lighting"
|
|
|
170
198
|
# Text-to-image (no input)
|
|
171
199
|
npx makaron-cli edit "a cyberpunk cityscape at night"
|
|
172
200
|
|
|
173
|
-
# With model/
|
|
174
|
-
npx makaron-cli edit --image photo.jpg --model openai --skill captions "add title"
|
|
201
|
+
# With model/reference
|
|
175
202
|
npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
176
203
|
|
|
177
204
|
# Output to file
|
|
178
205
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
179
206
|
```
|
|
180
207
|
|
|
181
|
-
Options: `--image`, `--model gemini|qwen|openai|pony|wai`, `--
|
|
208
|
+
Options: `--image`, `--model gemini|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path>`
|
|
182
209
|
|
|
183
210
|
### `video` — Standalone video tools (no project timeline)
|
|
184
211
|
|
|
@@ -237,8 +264,15 @@ type MakaronOutput =
|
|
|
237
264
|
| { id: string; type: "text"; status: "completed"; content: string }
|
|
238
265
|
| { id: string; type: "image"; status: "completed"; url: string; snapshot_id: string }
|
|
239
266
|
| { id: string; type: "design"; status: "completed"; url: string; width: number; height: number; animated: boolean; duration?: number }
|
|
240
|
-
| { id: string; type: "video"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; url?: string; elapsed_seconds?: number }
|
|
267
|
+
| { id: string; type: "video"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; snapshot_id?: string; url?: string; elapsed_seconds?: number; width?: number; height?: number; error?: string; completion_actions?: CompletionAction[] }
|
|
241
268
|
| { id: string; type: "music"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; url?: string; elapsed_seconds?: number }
|
|
269
|
+
|
|
270
|
+
type CompletionAction = {
|
|
271
|
+
label: string
|
|
272
|
+
prompt: string
|
|
273
|
+
description?: string
|
|
274
|
+
policy?: "confirm" | "auto"
|
|
275
|
+
}
|
|
242
276
|
```
|
|
243
277
|
|
|
244
278
|
## Polling Rules
|
|
@@ -247,6 +281,7 @@ type MakaronOutput =
|
|
|
247
281
|
2. Use `next_poll_after_ms` as interval (default 5000ms)
|
|
248
282
|
3. Stop when `status` is `"completed"`, `"failed"`, or `"aborted"`
|
|
249
283
|
4. Top-level `status: "completed"` means ALL artifacts are ready (including rendered videos)
|
|
284
|
+
5. If an async video fails, top-level `status` is `"failed"` and the failed video may include `completion_actions` for a safe retry or diagnosis. Agents can surface these as the next user-confirmed step.
|
|
250
285
|
|
|
251
286
|
## Exit Codes
|
|
252
287
|
|
|
@@ -266,6 +301,7 @@ type MakaronOutput =
|
|
|
266
301
|
| Text-to-image | "generate a cyberpunk cityscape" |
|
|
267
302
|
| Video from image | "create a 5 second video of her walking" |
|
|
268
303
|
| Video with model | "use seedance model, make a 5s video" |
|
|
304
|
+
| Real MP4 edits | `--video clip.mp4 "trim this to the best 20 seconds and preserve audio"` |
|
|
269
305
|
| **Edit video** | **"put Iron Man armor on me in this video"** |
|
|
270
306
|
| **Compose videos** | **"combine @1 and @2 into one party video"** |
|
|
271
307
|
| **Extend video** | **"continue the story for 10 more seconds"** |
|
|
@@ -320,6 +356,7 @@ send_message "All done!"
|
|
|
320
356
|
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|
|
321
357
|
- Always use `chat` as the primary interface — even for single image edits.
|
|
322
358
|
- `edit`/`video`/`music` are fallback tools for when `chat` is unavailable or you need raw model access without project context.
|
|
359
|
+
- The CLI checks npm for updates at most once per day and prints update notices to stderr. Set `MAKARON_DISABLE_UPDATE_CHECK=1` to disable it.
|
|
323
360
|
|
|
324
361
|
## Admin: Skill Marketplace Operations
|
|
325
362
|
|
package/bin/makaron.mjs
CHANGED
|
@@ -19,9 +19,13 @@ import { execFileSync } from 'child_process';
|
|
|
19
19
|
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
20
20
|
|
|
21
21
|
const AUTH_FILE = path.join(process.env.HOME || '~', '.makaron', 'auth.json');
|
|
22
|
+
const UPDATE_CHECK_FILE = path.join(process.env.HOME || '~', '.makaron', 'update-check.json');
|
|
22
23
|
const DEFAULT_URL = 'https://www.makaron.app';
|
|
23
24
|
const BASE_URL = process.env.MAKARON_URL || DEFAULT_URL;
|
|
24
25
|
const APP_URL = process.env.MAKARON_APP_URL || DEFAULT_URL;
|
|
26
|
+
const NPM_PACKAGE_NAME = 'makaron-cli';
|
|
27
|
+
const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
28
|
+
const UPDATE_CHECK_TIMEOUT_MS = 400;
|
|
25
29
|
|
|
26
30
|
// Public anon key (safe to embed — only enables auth, not data access)
|
|
27
31
|
const SUPABASE_URL = 'https://sdyrtztrjgmmpnirswxt.supabase.co';
|
|
@@ -49,6 +53,84 @@ function getCliVersion() {
|
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
function compareVersions(a, b) {
|
|
57
|
+
const parse = (version) => String(version || '')
|
|
58
|
+
.split('-')[0]
|
|
59
|
+
.split('.')
|
|
60
|
+
.map(part => Number.parseInt(part, 10) || 0);
|
|
61
|
+
const left = parse(a);
|
|
62
|
+
const right = parse(b);
|
|
63
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
64
|
+
const diff = (left[i] || 0) - (right[i] || 0);
|
|
65
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
66
|
+
}
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readUpdateCache() {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(fs.readFileSync(UPDATE_CHECK_FILE, 'utf-8'));
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function writeUpdateCache(data) {
|
|
79
|
+
try {
|
|
80
|
+
const dir = path.dirname(UPDATE_CHECK_FILE);
|
|
81
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
82
|
+
fs.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify(data, null, 2));
|
|
83
|
+
} catch { /* best effort */ }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function shouldCheckForUpdates(command, args) {
|
|
87
|
+
if (!command || command === '--version' || command === '-v' || command === 'version') return false;
|
|
88
|
+
if (args.includes('--help') || args.includes('-h')) return false;
|
|
89
|
+
if (args.includes('--json') || args.includes('--jsonl') || args.includes('--pick')) return false;
|
|
90
|
+
if (process.env.CI || process.env.NO_UPDATE_NOTIFIER || process.env.MAKARON_DISABLE_UPDATE_CHECK) return false;
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function maybeNotifyUpdate(command, args) {
|
|
95
|
+
if (!shouldCheckForUpdates(command, args)) return;
|
|
96
|
+
const currentVersion = getCliVersion();
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const cache = readUpdateCache();
|
|
99
|
+
if (cache?.checkedAt && now - cache.checkedAt < UPDATE_CHECK_INTERVAL_MS) {
|
|
100
|
+
if (cache.latestVersion && compareVersions(cache.latestVersion, currentVersion) > 0) {
|
|
101
|
+
printUpdateNotice(currentVersion, cache.latestVersion);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const timer = setTimeout(() => controller.abort(), UPDATE_CHECK_TIMEOUT_MS);
|
|
108
|
+
try {
|
|
109
|
+
const res = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`, {
|
|
110
|
+
signal: controller.signal,
|
|
111
|
+
headers: { 'Accept': 'application/json' },
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) return;
|
|
114
|
+
const data = await res.json();
|
|
115
|
+
const latestVersion = data?.version;
|
|
116
|
+
if (!latestVersion) return;
|
|
117
|
+
writeUpdateCache({ checkedAt: now, latestVersion });
|
|
118
|
+
if (compareVersions(latestVersion, currentVersion) > 0) {
|
|
119
|
+
printUpdateNotice(currentVersion, latestVersion);
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
writeUpdateCache({ checkedAt: now, latestVersion: cache?.latestVersion || currentVersion });
|
|
123
|
+
} finally {
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function printUpdateNotice(currentVersion, latestVersion) {
|
|
129
|
+
process.stderr.write(`\nUpdate available: makaron-cli ${currentVersion} -> ${latestVersion}\n`);
|
|
130
|
+
process.stderr.write('Run: npm install -g makaron-cli@latest\n');
|
|
131
|
+
process.stderr.write('Or: npx makaron-cli@latest ...\n\n');
|
|
132
|
+
}
|
|
133
|
+
|
|
52
134
|
function formatSeconds(seconds) {
|
|
53
135
|
if (!Number.isFinite(seconds)) return String(seconds);
|
|
54
136
|
return Number.isInteger(seconds) ? String(seconds) : seconds.toFixed(1).replace(/\.0$/, '');
|
|
@@ -153,6 +235,80 @@ function normalizeRunResponse(data) {
|
|
|
153
235
|
return data;
|
|
154
236
|
}
|
|
155
237
|
|
|
238
|
+
function collectCompletionActions(data) {
|
|
239
|
+
const items = [];
|
|
240
|
+
const add = (action, source) => {
|
|
241
|
+
if (!action?.label || !action?.prompt) return;
|
|
242
|
+
const key = `${action.label}\n${action.prompt}`;
|
|
243
|
+
if (items.some(i => i.key === key)) return;
|
|
244
|
+
items.push({ key, label: action.label, prompt: action.prompt, description: action.description, source });
|
|
245
|
+
};
|
|
246
|
+
for (const out of data.output || []) {
|
|
247
|
+
for (const action of out.completion_actions || out.completionActions || []) add(action, out.id || out.task_id);
|
|
248
|
+
}
|
|
249
|
+
for (const video of data.result?.videos || []) {
|
|
250
|
+
for (const action of video.completion_actions || video.completionActions || []) add(action, video.taskId);
|
|
251
|
+
}
|
|
252
|
+
return items;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function printCompletionActions(data) {
|
|
256
|
+
const projectId = data.projectId || data.project_id;
|
|
257
|
+
const actions = collectCompletionActions(data);
|
|
258
|
+
if (!projectId || actions.length === 0) return;
|
|
259
|
+
process.stderr.write('\nNext steps:\n');
|
|
260
|
+
for (const action of actions) {
|
|
261
|
+
process.stderr.write(`• ${action.label}${action.description ? ` — ${action.description}` : ''}\n`);
|
|
262
|
+
process.stderr.write(` makaron chat --project ${projectId} ${JSON.stringify(action.prompt)}\n`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function printChatHelp() {
|
|
267
|
+
console.log(`Makaron chat — create and edit with Makaron Agent
|
|
268
|
+
|
|
269
|
+
Usage:
|
|
270
|
+
makaron chat --project <id|auto> [options] "your message"
|
|
271
|
+
|
|
272
|
+
Options:
|
|
273
|
+
--project <id|auto> Project to work in. Use "auto" to create one.
|
|
274
|
+
--image <file|url> Attach a reference image or screenshot. Repeatable.
|
|
275
|
+
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
276
|
+
--model <name> Preferred image/model route.
|
|
277
|
+
--video-model <name> Preferred video model.
|
|
278
|
+
--background, -b Submit and print a runId.
|
|
279
|
+
--json Output structured JSON.
|
|
280
|
+
--stream Legacy live SSE stream.
|
|
281
|
+
--help, -h Show this help.
|
|
282
|
+
|
|
283
|
+
What you can ask:
|
|
284
|
+
Image edit
|
|
285
|
+
makaron chat --project <id> --image photo.jpg "remove the person in the background"
|
|
286
|
+
|
|
287
|
+
Image generation
|
|
288
|
+
makaron chat --project auto "generate a cinematic poster of a rainy Tokyo alley"
|
|
289
|
+
|
|
290
|
+
Video from image or timeline
|
|
291
|
+
makaron chat --project <id> "make this into a 5 second cinematic video"
|
|
292
|
+
|
|
293
|
+
Fix one video moment from a screenshot
|
|
294
|
+
makaron chat --project <id> --image screenshot.png "@4 this frame should be Paris; only fix this moment"
|
|
295
|
+
|
|
296
|
+
Video cuts and assembly
|
|
297
|
+
makaron chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"
|
|
298
|
+
|
|
299
|
+
Music
|
|
300
|
+
makaron chat --project <id> "add calm piano background music"
|
|
301
|
+
|
|
302
|
+
Motion design
|
|
303
|
+
makaron chat --project <id> "make an animated Instagram story with this image"
|
|
304
|
+
|
|
305
|
+
After async generation:
|
|
306
|
+
The CLI waits for video/music tasks. If the result has a natural next step, it prints:
|
|
307
|
+
Next steps:
|
|
308
|
+
makaron chat --project <id> "..."
|
|
309
|
+
`);
|
|
310
|
+
}
|
|
311
|
+
|
|
156
312
|
// ─── SSE Consumer ────────────────────────────────────────────────────────────
|
|
157
313
|
|
|
158
314
|
async function abortRun(baseUrl, headers, runId) {
|
|
@@ -399,6 +555,7 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
399
555
|
else if (v.status === 'failed') process.stderr.write(`🎬 Video ${v.taskId}: failed${v.error ? ` — ${v.error}` : ''}\n`);
|
|
400
556
|
else process.stderr.write(`🎬 Video ${v.taskId}: ${v.status || 'submitted'}\n`);
|
|
401
557
|
}
|
|
558
|
+
printCompletionActions(data);
|
|
402
559
|
for (const m of data.result.music || []) {
|
|
403
560
|
if (m.audioUrl) process.stderr.write(`🎵 Music: ${m.audioUrl}\n`);
|
|
404
561
|
else process.stderr.write(`🎵 Music ${m.taskId}: ${m.status || 'submitted'}\n`);
|
|
@@ -426,6 +583,12 @@ function applyPick(data, field) {
|
|
|
426
583
|
case 'design_urls': return (data.output || []).filter(o => o.type === 'design' && o.url).map(o => o.url);
|
|
427
584
|
case 'first_music_url': return data.output?.find(o => o.type === 'music' && o.url)?.url || null;
|
|
428
585
|
case 'music_urls': return (data.output || []).filter(o => o.type === 'music' && o.url).map(o => o.url);
|
|
586
|
+
case 'next_steps': return collectCompletionActions(data).map(action => ({
|
|
587
|
+
label: action.label,
|
|
588
|
+
prompt: action.prompt,
|
|
589
|
+
description: action.description,
|
|
590
|
+
source: action.source,
|
|
591
|
+
}));
|
|
429
592
|
case 'project_url': return data.project_url || data.projectUrl || null;
|
|
430
593
|
case 'output': return data.output || [];
|
|
431
594
|
case 'text': return data.output?.find(o => o.type === 'text')?.content || null;
|
|
@@ -995,6 +1158,8 @@ function printHelp(topic, subtopic) {
|
|
|
995
1158
|
const args = process.argv.slice(2);
|
|
996
1159
|
const command = args[0];
|
|
997
1160
|
|
|
1161
|
+
await maybeNotifyUpdate(command, args);
|
|
1162
|
+
|
|
998
1163
|
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
999
1164
|
printRootHelp();
|
|
1000
1165
|
} else if (hasHelpFlag(args)) {
|
|
@@ -1019,7 +1184,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1019
1184
|
}
|
|
1020
1185
|
await createProject(baseUrl, headers, opts);
|
|
1021
1186
|
} else if (command === 'chat') {
|
|
1022
|
-
|
|
1187
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1188
|
+
printChatHelp();
|
|
1189
|
+
process.exit(0);
|
|
1190
|
+
}
|
|
1023
1191
|
let projectId = null;
|
|
1024
1192
|
const chatImages = [];
|
|
1025
1193
|
const chatVideos = [];
|
|
@@ -1027,12 +1195,14 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1027
1195
|
let useStream = false;
|
|
1028
1196
|
let background = false;
|
|
1029
1197
|
let jsonOutput = false;
|
|
1198
|
+
let activeSkill = undefined;
|
|
1030
1199
|
let videoModel = undefined;
|
|
1031
1200
|
let preferredModel = undefined;
|
|
1032
1201
|
for (let i = 1; i < args.length; i++) {
|
|
1033
1202
|
if (args[i] === '--project' && args[i + 1]) projectId = args[++i];
|
|
1034
1203
|
else if (args[i] === '--image' && args[i + 1]) chatImages.push(args[++i]);
|
|
1035
1204
|
else if (args[i] === '--video' && args[i + 1]) chatVideos.push(args[++i]);
|
|
1205
|
+
else if (args[i] === '--skill' && args[i + 1]) activeSkill = args[++i];
|
|
1036
1206
|
else if (args[i] === '--stream') useStream = true;
|
|
1037
1207
|
else if (args[i] === '--background' || args[i] === '-b') background = true;
|
|
1038
1208
|
else if (args[i] === '--json') jsonOutput = true;
|
|
@@ -1042,9 +1212,11 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1042
1212
|
}
|
|
1043
1213
|
const prompt = promptParts.join(' ');
|
|
1044
1214
|
if (!prompt) {
|
|
1045
|
-
console.error('Usage: makaron chat --project <id|auto> [
|
|
1215
|
+
console.error('Usage: makaron chat --project <id|auto> [options] "your message"');
|
|
1216
|
+
console.error('Run: makaron chat --help');
|
|
1046
1217
|
process.exit(1);
|
|
1047
1218
|
}
|
|
1219
|
+
const { headers, baseUrl } = getAuth();
|
|
1048
1220
|
// Split images into URLs vs local files
|
|
1049
1221
|
const imageUrlList = chatImages.filter(p => p.startsWith('http://') || p.startsWith('https://'));
|
|
1050
1222
|
const imageFileList = chatImages.filter(p => !p.startsWith('http://') && !p.startsWith('https://'));
|
|
@@ -1122,7 +1294,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1122
1294
|
}
|
|
1123
1295
|
|
|
1124
1296
|
// Upload videos to project timeline (via /api/projects/create with videoUrls)
|
|
1125
|
-
let finalPrompt = prompt;
|
|
1297
|
+
let finalPrompt = activeSkill ? `[Active skill: ${activeSkill}]\n${prompt}` : prompt;
|
|
1126
1298
|
if (chatVideos.length > 0) {
|
|
1127
1299
|
// Upload local files via signed URL (no size limit, works with API key auth)
|
|
1128
1300
|
const uploadedVideoUrls = [...prevalidatedVideoUrlList];
|
|
@@ -1166,7 +1338,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1166
1338
|
|
|
1167
1339
|
// Inject hint so Agent knows videos are available
|
|
1168
1340
|
const hint = `[User uploaded ${chatVideos.length === 1 ? 'a video' : `${chatVideos.length} videos`}. Use analyze_video to understand the content.]`;
|
|
1169
|
-
finalPrompt = `${
|
|
1341
|
+
finalPrompt = `${finalPrompt}\n\n${hint}`;
|
|
1170
1342
|
}
|
|
1171
1343
|
|
|
1172
1344
|
if (useStream) {
|
|
@@ -1311,7 +1483,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1311
1483
|
else promptParts.push(args[i]);
|
|
1312
1484
|
}
|
|
1313
1485
|
editArgs.editPrompt = promptParts.join(' ');
|
|
1314
|
-
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--model gemini|qwen|openai] [--
|
|
1486
|
+
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--model gemini|qwen|openai] [--ref <file>] [--out <file>] "prompt"'); process.exit(1); }
|
|
1315
1487
|
process.stderr.write('🎨 Generating...\n');
|
|
1316
1488
|
const result = await callMcpTool(baseUrl, headers, 'makaron_edit_image', editArgs);
|
|
1317
1489
|
saveMcpImage(result, outputPath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Talk to Makaron Agent from the terminal — create projects, edit images, generate videos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"skills/",
|
|
17
17
|
".codex-plugin/",
|
|
18
18
|
".claude-plugin/",
|
|
19
|
-
"SKILL.md",
|
|
20
19
|
"README.md"
|
|
21
20
|
],
|
|
22
21
|
"keywords": [
|
package/skills/makaron/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: makaron
|
|
3
|
-
description: Use Makaron CLI to generate AI images, videos, music, and motion designs. Trigger when user needs creative media production — photo editing, video generation, music composition, or design creation. Requires `npx makaron-cli` and MAKARON_API_KEY env var.
|
|
3
|
+
description: Use Makaron CLI to generate AI images, videos, music, and motion designs. Trigger when user needs creative media production — photo editing, video generation, video editing, music composition, or design creation. Requires `npx makaron-cli` and MAKARON_API_KEY env var.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Makaron CLI — Agent Integration Skill
|
|
@@ -64,6 +64,10 @@ npx makaron-cli responses get $RUN_ID --wait --json
|
|
|
64
64
|
|
|
65
65
|
Use `chat` for all creative tasks. Makaron Agent decides how to execute — it can edit images, generate videos, compose music, and create designs in a single conversation.
|
|
66
66
|
|
|
67
|
+
```bash
|
|
68
|
+
npx makaron-cli chat --help
|
|
69
|
+
```
|
|
70
|
+
|
|
67
71
|
### Submit a request
|
|
68
72
|
|
|
69
73
|
```bash
|
|
@@ -80,6 +84,18 @@ Returns immediately:
|
|
|
80
84
|
{"runId": "xxx", "projectId": "...", "projectUrl": "https://www.makaron.app/projects/...", "status": "running"}
|
|
81
85
|
```
|
|
82
86
|
|
|
87
|
+
### Common workflows
|
|
88
|
+
|
|
89
|
+
| What you want | Example |
|
|
90
|
+
|--------------|---------|
|
|
91
|
+
| Edit an image | `npx makaron-cli chat --project <id> --image photo.jpg "remove the person in the background"` |
|
|
92
|
+
| Generate an image | `npx makaron-cli chat --project auto "generate a cinematic poster of a rainy Tokyo alley"` |
|
|
93
|
+
| Make a video from the current project | `npx makaron-cli chat --project <id> "make this into a 5 second cinematic video"` |
|
|
94
|
+
| 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"` |
|
|
95
|
+
| Cut or assemble video | `npx makaron-cli chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"` |
|
|
96
|
+
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
97
|
+
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
98
|
+
|
|
83
99
|
### With additional images (existing project)
|
|
84
100
|
|
|
85
101
|
```bash
|
|
@@ -116,6 +132,18 @@ Supported formats: MP4, MOV, WebM. CLI local video uploads support max 50MB, max
|
|
|
116
132
|
|
|
117
133
|
Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct video commands are standalone raw-tool calls.
|
|
118
134
|
|
|
135
|
+
### Fix one video moment from a screenshot
|
|
136
|
+
|
|
137
|
+
When a video is mostly good but one moment needs a local fix, attach a screenshot of the problem frame and describe the correction in normal language:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx makaron-cli chat --project <id> \
|
|
141
|
+
--image screenshot.png \
|
|
142
|
+
"@4 this frame should be Paris, keep the same style and only fix this moment"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Makaron can locate the screenshot in the video, regenerate only the nearby segment, and then print a `Next steps` command when the new clip should be stitched back into the full MP4.
|
|
146
|
+
|
|
119
147
|
### Check status (single query)
|
|
120
148
|
|
|
121
149
|
```bash
|
|
@@ -162,15 +190,14 @@ npx makaron-cli edit --image photo.jpg "add cinematic warm lighting"
|
|
|
162
190
|
# Text-to-image (no input)
|
|
163
191
|
npx makaron-cli edit "a cyberpunk cityscape at night"
|
|
164
192
|
|
|
165
|
-
# With model/
|
|
166
|
-
npx makaron-cli edit --image photo.jpg --model openai --skill captions "add title"
|
|
193
|
+
# With model/reference
|
|
167
194
|
npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
168
195
|
|
|
169
196
|
# Output to file
|
|
170
197
|
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
171
198
|
```
|
|
172
199
|
|
|
173
|
-
Options: `--image`, `--model gemini|qwen|openai|pony|wai`, `--
|
|
200
|
+
Options: `--image`, `--model gemini|qwen|openai|pony|wai`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path>`
|
|
174
201
|
|
|
175
202
|
### `video` — Standalone video tools (no project timeline)
|
|
176
203
|
|
|
@@ -229,8 +256,15 @@ type MakaronOutput =
|
|
|
229
256
|
| { id: string; type: "text"; status: "completed"; content: string }
|
|
230
257
|
| { id: string; type: "image"; status: "completed"; url: string; snapshot_id: string }
|
|
231
258
|
| { id: string; type: "design"; status: "completed"; url: string; width: number; height: number; animated: boolean; duration?: number }
|
|
232
|
-
| { id: string; type: "video"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; snapshot_id?: string; url?: string; elapsed_seconds?: number; width?: number; height?: number }
|
|
259
|
+
| { id: string; type: "video"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; snapshot_id?: string; url?: string; elapsed_seconds?: number; width?: number; height?: number; error?: string; completion_actions?: CompletionAction[] }
|
|
233
260
|
| { id: string; type: "music"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; url?: string; elapsed_seconds?: number }
|
|
261
|
+
|
|
262
|
+
type CompletionAction = {
|
|
263
|
+
label: string
|
|
264
|
+
prompt: string
|
|
265
|
+
description?: string
|
|
266
|
+
policy?: "confirm" | "auto"
|
|
267
|
+
}
|
|
234
268
|
```
|
|
235
269
|
|
|
236
270
|
## Polling Rules
|
|
@@ -239,6 +273,7 @@ type MakaronOutput =
|
|
|
239
273
|
2. Use `next_poll_after_ms` as interval (default 5000ms)
|
|
240
274
|
3. Stop when `status` is `"completed"`, `"failed"`, or `"aborted"`
|
|
241
275
|
4. Top-level `status: "completed"` means ALL artifacts are ready (including rendered videos)
|
|
276
|
+
5. If an async video fails, top-level `status` is `"failed"` and the failed video may include `completion_actions` for a safe retry or diagnosis. Agents can surface these as the next user-confirmed step.
|
|
242
277
|
|
|
243
278
|
## Exit Codes
|
|
244
279
|
|
|
@@ -258,6 +293,7 @@ type MakaronOutput =
|
|
|
258
293
|
| Text-to-image | "generate a cyberpunk cityscape" |
|
|
259
294
|
| Video from image | "create a 5 second video of her walking" |
|
|
260
295
|
| Video with model | "use seedance model, make a 5s video" |
|
|
296
|
+
| Real MP4 edits | `--video clip.mp4 "trim this to the best 20 seconds and preserve audio"` |
|
|
261
297
|
| Background music | "add calm piano music" |
|
|
262
298
|
| Motion design | "create an Instagram story with animated text" |
|
|
263
299
|
| Multi-step | "edit the photo then make a video from it" |
|
package/SKILL.md
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: makaron
|
|
3
|
-
description: Use Makaron CLI to generate AI images, videos, music, and motion designs. Trigger when user needs creative media production — photo editing, video generation, music composition, or design creation. Requires `npx makaron-cli` and MAKARON_API_KEY env var.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Makaron CLI — Agent Integration Skill
|
|
7
|
-
|
|
8
|
-
> **makaron.app** is for humans. **makaron-cli** is for AI agents.
|
|
9
|
-
|
|
10
|
-
Makaron is a multimodal AI creative agent. You talk to it via `makaron chat`, and it produces images, videos, music, and animated designs — all saved to a persistent project.
|
|
11
|
-
|
|
12
|
-
## Setup
|
|
13
|
-
|
|
14
|
-
### Get your API key
|
|
15
|
-
|
|
16
|
-
**Option A: Human login**
|
|
17
|
-
1. Go to [makaron.app](https://makaron.app) and log in
|
|
18
|
-
2. Open the menu (top-right) → **Get API Key**
|
|
19
|
-
3. Copy your `mk_live_...` key
|
|
20
|
-
|
|
21
|
-
**Option B: Self-Registration (no human required)**
|
|
22
|
-
```bash
|
|
23
|
-
# Step 1: Get challenge
|
|
24
|
-
npx makaron-cli register --json
|
|
25
|
-
# → { "challenge_id": "...", "challenge": "...", "expected_format": "numeric, round to 2 decimal places" }
|
|
26
|
-
|
|
27
|
-
# Step 2: Solve and verify
|
|
28
|
-
npx makaron-cli register --verify --challenge-id <id> --answer 34.5
|
|
29
|
-
# → Key saved to ~/.makaron/auth.json
|
|
30
|
-
# → { "api_key": "mk_live_...", "credits": N, "claim_url": "..." }
|
|
31
|
-
|
|
32
|
-
# (Optional) Let a human claim this account
|
|
33
|
-
npx makaron-cli claim
|
|
34
|
-
# → { "claim_url": "..." } — share with human to link key to their account (valid 7 days)
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Discovery endpoint: `GET https://www.makaron.app/api/agent/register` — returns full registration flow + CLI usage as JSON.
|
|
38
|
-
|
|
39
|
-
After self-registration the key is saved locally — no need to export `MAKARON_API_KEY`.
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
export MAKARON_API_KEY=mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Verify: `npx makaron-cli list` should show projects.
|
|
46
|
-
|
|
47
|
-
## Core Workflow
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# One-shot: create project + upload image + submit prompt — all in one command
|
|
51
|
-
RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinematic and create a 5s video")
|
|
52
|
-
|
|
53
|
-
# Wait for the final customer-ready result
|
|
54
|
-
npx makaron-cli responses get $RUN_ID --wait --json
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Or with an existing project:
|
|
58
|
-
```bash
|
|
59
|
-
RUN_ID=$(npx makaron-cli chat --project $PROJECT_ID -b "make a 5s video")
|
|
60
|
-
npx makaron-cli responses get $RUN_ID --wait --json
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Primary: `chat` (Agent-driven creative work)
|
|
64
|
-
|
|
65
|
-
Use `chat` for all creative tasks. Makaron Agent decides how to execute — it can edit images, generate videos, compose music, and create designs in a single conversation.
|
|
66
|
-
|
|
67
|
-
### Submit a request
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
# With existing project
|
|
71
|
-
npx makaron-cli chat --project <id> --json -b "<prompt>"
|
|
72
|
-
|
|
73
|
-
# Auto-create project (with or without images)
|
|
74
|
-
npx makaron-cli chat --project auto --image photo.jpg --json -b "make it cinematic"
|
|
75
|
-
npx makaron-cli chat --project auto --image img1.jpg --image img2.jpg --json -b "combine these"
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Returns immediately:
|
|
79
|
-
```json
|
|
80
|
-
{"runId": "xxx", "projectId": "...", "projectUrl": "https://www.makaron.app/projects/...", "status": "running"}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### With additional images (existing project)
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npx makaron-cli chat --project <id> --image ref1.jpg --image ref2.jpg -b "use these as style reference"
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Inspect existing timeline media
|
|
90
|
-
|
|
91
|
-
Before starting a follow-up run on an existing project, list the current timeline media so you know what assets are available and which `<<<media_N>>>` references to use:
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
npx makaron-cli project media <projectId> --json
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
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.
|
|
98
|
-
|
|
99
|
-
### With video input (edit, compose, extend)
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
# Upload a video and transform it — Agent understands video content natively
|
|
103
|
-
npx makaron-cli chat --project auto --video selfie.mp4 -b "put Iron Man armor on me"
|
|
104
|
-
|
|
105
|
-
# Combine a person's photo with a video scene
|
|
106
|
-
npx makaron-cli chat --project <id> --video party.mp4 --image kid.jpg -b "make this kid join the party"
|
|
107
|
-
|
|
108
|
-
# Multiple videos — compose or splice
|
|
109
|
-
npx makaron-cli chat --project <id> --video clip1.mp4 --video clip2.mp4 -b "combine into one seamless video"
|
|
110
|
-
|
|
111
|
-
# Video URL (public, downloadable)
|
|
112
|
-
npx makaron-cli chat --project auto --video https://example.com/dance.mp4 -b "extend this to 15 seconds"
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Supported formats: MP4, MOV, WebM. CLI local video uploads support max 50MB, max 120s with 1s metadata tolerance, and <=1080p / 2,086,876 frame pixels. The frontend can transcode larger videos before upload; the CLI uploads directly to Storage and rejects videos above those limits. Videos are uploaded to the project timeline. The Agent can analyze scenes, edit content, compose multiple clips, extend duration, and add effects — all via natural language. Seedance video-reference editing is still limited to ~15s provider references, so longer uploaded videos should be split/prepared by the agent before model submission; Kling remains the base/direct edit path.
|
|
116
|
-
|
|
117
|
-
Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct video commands are standalone raw-tool calls.
|
|
118
|
-
|
|
119
|
-
### Check status (single query)
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
npx makaron-cli responses get <runId> --json
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Advanced: stream incremental events
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npx makaron-cli responses watch <runId> --jsonl
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Outputs one JSON per line as artifacts appear:
|
|
132
|
-
```
|
|
133
|
-
{"event":"output.added","item":{"id":"out_1","type":"image","status":"completed","url":"https://..."}}
|
|
134
|
-
{"event":"output.added","item":{"id":"out_2","type":"video","status":"rendering","task_id":"xxx"}}
|
|
135
|
-
{"event":"output.updated","item":{"id":"out_2","type":"video","status":"completed","url":"https://..."}}
|
|
136
|
-
{"event":"done","status":"completed"}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Extract specific results
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
npx makaron-cli responses get <runId> --pick first_image_url
|
|
143
|
-
npx makaron-cli responses get <runId> --pick image_urls # all images (JSON array)
|
|
144
|
-
npx makaron-cli responses get <runId> --pick first_video_url
|
|
145
|
-
npx makaron-cli responses get <runId> --pick video_urls # all videos
|
|
146
|
-
npx makaron-cli responses get <runId> --pick project_url
|
|
147
|
-
npx makaron-cli responses get <runId> --pick text # agent's text reply
|
|
148
|
-
npx makaron-cli responses get <runId> --pick output # full output array
|
|
149
|
-
npx makaron-cli responses get <runId> --pick status
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Fallback: Direct tool calls (no project context)
|
|
153
|
-
|
|
154
|
-
Use these only when `chat` is unavailable or you need raw model access without project/conversation context.
|
|
155
|
-
|
|
156
|
-
### `edit` — One-shot image editing
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
# Edit an existing image
|
|
160
|
-
npx makaron-cli edit --image photo.jpg "add cinematic warm lighting"
|
|
161
|
-
|
|
162
|
-
# Text-to-image (no input)
|
|
163
|
-
npx makaron-cli edit "a cyberpunk cityscape at night"
|
|
164
|
-
|
|
165
|
-
# With model/skill/reference
|
|
166
|
-
npx makaron-cli edit --image photo.jpg --model openai --skill captions "add title"
|
|
167
|
-
npx makaron-cli edit --image photo.jpg --ref style.jpg "match this style"
|
|
168
|
-
|
|
169
|
-
# Output to file
|
|
170
|
-
npx makaron-cli edit --image photo.jpg --out result.jpg "make it dramatic"
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Options: `--image`, `--model gemini|qwen|openai|pony|wai`, `--skill enhance|creative|wild|captions`, `--ref <file>` (up to 3), `--aspect <ratio>`, `--out <path>`
|
|
174
|
-
|
|
175
|
-
### `video` — Standalone video tools (no project timeline)
|
|
176
|
-
|
|
177
|
-
```bash
|
|
178
|
-
# 1. Write script from images
|
|
179
|
-
npx makaron-cli video script --image img1.jpg "cinematic story"
|
|
180
|
-
|
|
181
|
-
# 2. Analyze a video (standalone, no timeline write)
|
|
182
|
-
npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
|
|
183
|
-
|
|
184
|
-
# 3a. Submit image-to-video rendering (images must be public URLs from step 1 or uploaded)
|
|
185
|
-
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --model kling
|
|
186
|
-
|
|
187
|
-
# 3b. Edit a video from a local file or public URL
|
|
188
|
-
npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance
|
|
189
|
-
npx makaron-cli video create --script "make it warmer and cinematic" --video https://example.com/input.mp4 --duration 5 --model seedance
|
|
190
|
-
|
|
191
|
-
# 4. Check status
|
|
192
|
-
npx makaron-cli video status <taskId>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
`video create` returns a provider task id and does not create or update a Makaron project timeline. For project/timeline video editing, use:
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
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 kling|seedance`. SeeDance accepts integer output duration 4-15s (default 5s); Kling supports 5-15s.
|
|
202
|
-
|
|
203
|
-
Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--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.
|
|
204
|
-
|
|
205
|
-
### `music` — Music generation
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
npx makaron-cli music create "gentle piano, warm strings, cinematic"
|
|
209
|
-
npx makaron-cli music create --vocals --style "lo-fi" "rainy day vibes"
|
|
210
|
-
npx makaron-cli music status <taskId>
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Options: `--vocals` (include vocals), `--style "genre"`
|
|
214
|
-
|
|
215
|
-
## Response Schema
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
type MakaronRunResponse = {
|
|
219
|
-
id: string
|
|
220
|
-
status: "in_progress" | "completed" | "failed" | "aborted"
|
|
221
|
-
incomplete: boolean // true = keep polling
|
|
222
|
-
project_id: string
|
|
223
|
-
project_url: string
|
|
224
|
-
next_poll_after_ms?: number // suggested poll interval
|
|
225
|
-
output: MakaronOutput[]
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
type MakaronOutput =
|
|
229
|
-
| { id: string; type: "text"; status: "completed"; content: string }
|
|
230
|
-
| { id: string; type: "image"; status: "completed"; url: string; snapshot_id: string }
|
|
231
|
-
| { id: string; type: "design"; status: "completed"; url: string; width: number; height: number; animated: boolean; duration?: number }
|
|
232
|
-
| { id: string; type: "video"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; snapshot_id?: string; url?: string; elapsed_seconds?: number; width?: number; height?: number }
|
|
233
|
-
| { id: string; type: "music"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; url?: string; elapsed_seconds?: number }
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
## Polling Rules
|
|
237
|
-
|
|
238
|
-
1. Poll while `incomplete: true` or `status` is `"in_progress"`
|
|
239
|
-
2. Use `next_poll_after_ms` as interval (default 5000ms)
|
|
240
|
-
3. Stop when `status` is `"completed"`, `"failed"`, or `"aborted"`
|
|
241
|
-
4. Top-level `status: "completed"` means ALL artifacts are ready (including rendered videos)
|
|
242
|
-
|
|
243
|
-
## Exit Codes
|
|
244
|
-
|
|
245
|
-
| Code | Meaning |
|
|
246
|
-
|------|---------|
|
|
247
|
-
| 0 | Success (completed) or valid in-progress response |
|
|
248
|
-
| 1 | Failed, aborted, or HTTP error |
|
|
249
|
-
| 2 | Timeout (partial response still printed to stdout) |
|
|
250
|
-
|
|
251
|
-
## What Makaron Agent Can Do
|
|
252
|
-
|
|
253
|
-
| Task | Example prompt |
|
|
254
|
-
|------|---------------|
|
|
255
|
-
| Edit photo | "make it cinematic with warm tones" |
|
|
256
|
-
| Style transfer | "convert to oil painting style" |
|
|
257
|
-
| Add/remove elements | "add a cat on the table" / "remove background person" |
|
|
258
|
-
| Text-to-image | "generate a cyberpunk cityscape" |
|
|
259
|
-
| Video from image | "create a 5 second video of her walking" |
|
|
260
|
-
| Video with model | "use seedance model, make a 5s video" |
|
|
261
|
-
| Background music | "add calm piano music" |
|
|
262
|
-
| Motion design | "create an Instagram story with animated text" |
|
|
263
|
-
| Multi-step | "edit the photo then make a video from it" |
|
|
264
|
-
|
|
265
|
-
## Recommended Pattern: Service Flow (Feishu/OpenClaw/Group Chat)
|
|
266
|
-
|
|
267
|
-
When serving end-users in a chat environment (Feishu, Slack, Discord), use this proactive message pattern:
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
# 1. Immediately acknowledge the user
|
|
271
|
-
send_message "Got it! Working on it now..."
|
|
272
|
-
|
|
273
|
-
# 2. Create project + submit (one command)
|
|
274
|
-
RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinematic and create a 5s video")
|
|
275
|
-
|
|
276
|
-
# 3. Send project link proactively
|
|
277
|
-
PROJECT_URL=$(npx makaron-cli responses get $RUN_ID --pick project_url)
|
|
278
|
-
send_message "Project created: $PROJECT_URL"
|
|
279
|
-
|
|
280
|
-
# 4. Wait for the final customer-ready result
|
|
281
|
-
RESULT=$(npx makaron-cli responses get $RUN_ID --wait --json)
|
|
282
|
-
IMAGE_URLS=$(echo "$RESULT" | jq -r '[.result.images[]?.imageUrl, .output[]? | select(.type == "image") | .url] | map(select(. != null)) | unique | .[]')
|
|
283
|
-
VIDEO_URLS=$(echo "$RESULT" | jq -r '[.result.videos[]?.videoUrl, .output[]? | select(.type == "video") | .url] | map(select(. != null)) | unique | .[]')
|
|
284
|
-
|
|
285
|
-
for URL in $IMAGE_URLS; do
|
|
286
|
-
send_image "$URL"
|
|
287
|
-
done
|
|
288
|
-
for URL in $VIDEO_URLS; do
|
|
289
|
-
send_video "$URL"
|
|
290
|
-
done
|
|
291
|
-
send_message "All done!"
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
**Key principles for service agents:**
|
|
295
|
-
- **Proactive, not silent**: Acknowledge immediately, send the project link early, then send the final customer-ready media when the run completes.
|
|
296
|
-
- **Media over links**: When possible, send images/videos as native media in the chat (download URL and upload as attachment), not just paste the URL.
|
|
297
|
-
- **Immediate acknowledgment**: Reply within 1 second of receiving user request. Don't make users wait for project creation.
|
|
298
|
-
- **Project link early**: Send the project URL right after creation so users can check anytime.
|
|
299
|
-
- **Use `get --wait --json` as the default service path**: reserve `watch --jsonl` for advanced streaming or debugging integrations that explicitly need incremental events.
|
|
300
|
-
|
|
301
|
-
## Important Notes
|
|
302
|
-
|
|
303
|
-
- One project = one conversation thread. All history is preserved.
|
|
304
|
-
- One run at a time per project. New message interrupts previous run.
|
|
305
|
-
- Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
|
|
306
|
-
- Videos take 2-5 minutes to render. Use `responses get <runId> --wait --json` for the default customer-service path.
|
|
307
|
-
- Music takes ~60 seconds. Appears in output when done.
|
|
308
|
-
- Images are typically ready in 15-30 seconds.
|
|
309
|
-
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|
|
310
|
-
- Always use `chat` as the primary interface — even for single image edits.
|
|
311
|
-
- `edit`/`video`/`music` are fallback tools for when `chat` is unavailable or you need raw model access without project context.
|