makaron-cli 0.8.4 → 0.10.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 +47 -9
- package/bin/makaron.mjs +194 -17
- package/package.json +1 -2
- package/skills/makaron/SKILL.md +46 -10
- 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
|
|
|
@@ -191,10 +218,11 @@ npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
|
|
|
191
218
|
|
|
192
219
|
# 3a. Submit image-to-video rendering (images must be public URLs from step 1 or uploaded)
|
|
193
220
|
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --model kling
|
|
221
|
+
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
|
|
194
222
|
|
|
195
223
|
# 3b. Edit a video from a local file or public URL
|
|
196
|
-
npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance
|
|
197
|
-
npx makaron-cli video create --script "make it warmer and cinematic" --video https://example.com/input.mp4 --duration 5 --model seedance
|
|
224
|
+
npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance-fast
|
|
225
|
+
npx makaron-cli video create --script "make it warmer and cinematic" --video https://example.com/input.mp4 --duration 5 --model seedance --video-resolution 1080p
|
|
198
226
|
|
|
199
227
|
# 4. Check status
|
|
200
228
|
npx makaron-cli video status <taskId>
|
|
@@ -206,9 +234,9 @@ For project/timeline video editing, use:
|
|
|
206
234
|
npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
|
|
207
235
|
```
|
|
208
236
|
|
|
209
|
-
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.
|
|
237
|
+
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.
|
|
210
238
|
|
|
211
|
-
Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance --video` uses the
|
|
239
|
+
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.
|
|
212
240
|
|
|
213
241
|
### `music` — Music generation
|
|
214
242
|
|
|
@@ -237,8 +265,15 @@ type MakaronOutput =
|
|
|
237
265
|
| { id: string; type: "text"; status: "completed"; content: string }
|
|
238
266
|
| { id: string; type: "image"; status: "completed"; url: string; snapshot_id: string }
|
|
239
267
|
| { 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 }
|
|
268
|
+
| { 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
269
|
| { id: string; type: "music"; status: "queued"|"rendering"|"completed"|"failed"; task_id: string; url?: string; elapsed_seconds?: number }
|
|
270
|
+
|
|
271
|
+
type CompletionAction = {
|
|
272
|
+
label: string
|
|
273
|
+
prompt: string
|
|
274
|
+
description?: string
|
|
275
|
+
policy?: "confirm" | "auto"
|
|
276
|
+
}
|
|
242
277
|
```
|
|
243
278
|
|
|
244
279
|
## Polling Rules
|
|
@@ -247,6 +282,7 @@ type MakaronOutput =
|
|
|
247
282
|
2. Use `next_poll_after_ms` as interval (default 5000ms)
|
|
248
283
|
3. Stop when `status` is `"completed"`, `"failed"`, or `"aborted"`
|
|
249
284
|
4. Top-level `status: "completed"` means ALL artifacts are ready (including rendered videos)
|
|
285
|
+
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
286
|
|
|
251
287
|
## Exit Codes
|
|
252
288
|
|
|
@@ -266,6 +302,7 @@ type MakaronOutput =
|
|
|
266
302
|
| Text-to-image | "generate a cyberpunk cityscape" |
|
|
267
303
|
| Video from image | "create a 5 second video of her walking" |
|
|
268
304
|
| Video with model | "use seedance model, make a 5s video" |
|
|
305
|
+
| Real MP4 edits | `--video clip.mp4 "trim this to the best 20 seconds and preserve audio"` |
|
|
269
306
|
| **Edit video** | **"put Iron Man armor on me in this video"** |
|
|
270
307
|
| **Compose videos** | **"combine @1 and @2 into one party video"** |
|
|
271
308
|
| **Extend video** | **"continue the story for 10 more seconds"** |
|
|
@@ -314,12 +351,13 @@ send_message "All done!"
|
|
|
314
351
|
- One project = one conversation thread. All history is preserved.
|
|
315
352
|
- One run at a time per project. New message interrupts previous run.
|
|
316
353
|
- Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
|
|
317
|
-
-
|
|
354
|
+
- Most videos take 3-5 minutes; Grok is usually around 30-40 seconds. Use `responses get <runId> --wait --json` for the default customer-service path.
|
|
318
355
|
- Music takes ~60 seconds. Appears in output when done.
|
|
319
356
|
- Images are typically ready in 15-30 seconds.
|
|
320
357
|
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|
|
321
358
|
- Always use `chat` as the primary interface — even for single image edits.
|
|
322
359
|
- `edit`/`video`/`music` are fallback tools for when `chat` is unavailable or you need raw model access without project context.
|
|
360
|
+
- 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
361
|
|
|
324
362
|
## Admin: Skill Marketplace Operations
|
|
325
363
|
|
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,81 @@ 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: seedance-fast, seedance, kling, or grok.
|
|
278
|
+
--video-resolution <res> Video resolution: auto, 480p, 720p, 1080p, or 4k.
|
|
279
|
+
--background, -b Submit and print a runId.
|
|
280
|
+
--json Output structured JSON.
|
|
281
|
+
--stream Legacy live SSE stream.
|
|
282
|
+
--help, -h Show this help.
|
|
283
|
+
|
|
284
|
+
What you can ask:
|
|
285
|
+
Image edit
|
|
286
|
+
makaron chat --project <id> --image photo.jpg "remove the person in the background"
|
|
287
|
+
|
|
288
|
+
Image generation
|
|
289
|
+
makaron chat --project auto "generate a cinematic poster of a rainy Tokyo alley"
|
|
290
|
+
|
|
291
|
+
Video from image or timeline
|
|
292
|
+
makaron chat --project <id> "make this into a 5 second cinematic video"
|
|
293
|
+
|
|
294
|
+
Fix one video moment from a screenshot
|
|
295
|
+
makaron chat --project <id> --image screenshot.png "@4 this frame should be Paris; only fix this moment"
|
|
296
|
+
|
|
297
|
+
Video cuts and assembly
|
|
298
|
+
makaron chat --project <id> --video clip.mp4 "cut out the dead air and keep the best 20 seconds"
|
|
299
|
+
|
|
300
|
+
Music
|
|
301
|
+
makaron chat --project <id> "add calm piano background music"
|
|
302
|
+
|
|
303
|
+
Motion design
|
|
304
|
+
makaron chat --project <id> "make an animated Instagram story with this image"
|
|
305
|
+
|
|
306
|
+
After async generation:
|
|
307
|
+
The CLI waits for video/music tasks. If the result has a natural next step, it prints:
|
|
308
|
+
Next steps:
|
|
309
|
+
makaron chat --project <id> "..."
|
|
310
|
+
`);
|
|
311
|
+
}
|
|
312
|
+
|
|
156
313
|
// ─── SSE Consumer ────────────────────────────────────────────────────────────
|
|
157
314
|
|
|
158
315
|
async function abortRun(baseUrl, headers, runId) {
|
|
@@ -285,6 +442,7 @@ async function submitRun(baseUrl, headers, projectId, prompt, opts = {}) {
|
|
|
285
442
|
const body = { projectId, prompt };
|
|
286
443
|
if (opts.preferredModel) body.preferredModel = opts.preferredModel;
|
|
287
444
|
if (opts.videoModel) body.videoModel = opts.videoModel;
|
|
445
|
+
if (opts.videoResolution) body.videoResolution = opts.videoResolution;
|
|
288
446
|
if (opts.currentSnapshotIndex != null) body.currentSnapshotIndex = opts.currentSnapshotIndex;
|
|
289
447
|
if (opts.isNsfw) body.isNsfw = opts.isNsfw;
|
|
290
448
|
|
|
@@ -399,6 +557,7 @@ async function pollRun(baseUrl, headers, runId, opts = {}) {
|
|
|
399
557
|
else if (v.status === 'failed') process.stderr.write(`🎬 Video ${v.taskId}: failed${v.error ? ` — ${v.error}` : ''}\n`);
|
|
400
558
|
else process.stderr.write(`🎬 Video ${v.taskId}: ${v.status || 'submitted'}\n`);
|
|
401
559
|
}
|
|
560
|
+
printCompletionActions(data);
|
|
402
561
|
for (const m of data.result.music || []) {
|
|
403
562
|
if (m.audioUrl) process.stderr.write(`🎵 Music: ${m.audioUrl}\n`);
|
|
404
563
|
else process.stderr.write(`🎵 Music ${m.taskId}: ${m.status || 'submitted'}\n`);
|
|
@@ -426,6 +585,12 @@ function applyPick(data, field) {
|
|
|
426
585
|
case 'design_urls': return (data.output || []).filter(o => o.type === 'design' && o.url).map(o => o.url);
|
|
427
586
|
case 'first_music_url': return data.output?.find(o => o.type === 'music' && o.url)?.url || null;
|
|
428
587
|
case 'music_urls': return (data.output || []).filter(o => o.type === 'music' && o.url).map(o => o.url);
|
|
588
|
+
case 'next_steps': return collectCompletionActions(data).map(action => ({
|
|
589
|
+
label: action.label,
|
|
590
|
+
prompt: action.prompt,
|
|
591
|
+
description: action.description,
|
|
592
|
+
source: action.source,
|
|
593
|
+
}));
|
|
429
594
|
case 'project_url': return data.project_url || data.projectUrl || null;
|
|
430
595
|
case 'output': return data.output || [];
|
|
431
596
|
case 'text': return data.output?.find(o => o.type === 'text')?.content || null;
|
|
@@ -950,12 +1115,12 @@ function printHelp(topic, subtopic) {
|
|
|
950
1115
|
console.log('Usage: makaron analyze --video <file|url> ["question"]');
|
|
951
1116
|
} else if (topic === 'video') {
|
|
952
1117
|
if (subtopic === 'script') console.log('Usage: makaron video script --image <file> [--image <file>] [--lang en|zh] "direction"');
|
|
953
|
-
else if (subtopic === 'create') console.log('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model kling|
|
|
1118
|
+
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]');
|
|
954
1119
|
else if (subtopic === 'status') console.log('Usage: makaron video status <taskId> | --snapshot <snapshotId> [--wait]');
|
|
955
1120
|
else console.log(`Video commands:
|
|
956
1121
|
video script --image <file> [--image <file>] "direction" Write video script
|
|
957
1122
|
video create --script "..." --image <url> [--duration 10] Submit video task
|
|
958
|
-
video create --script "..." --video <public-url> [--model
|
|
1123
|
+
video create --script "..." --video <public-url> [--model seedance-fast|seedance|kling] Edit a video (standalone; Grok does not support video refs)
|
|
959
1124
|
video status <taskId> Check video status
|
|
960
1125
|
video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
|
|
961
1126
|
`);
|
|
@@ -995,6 +1160,8 @@ function printHelp(topic, subtopic) {
|
|
|
995
1160
|
const args = process.argv.slice(2);
|
|
996
1161
|
const command = args[0];
|
|
997
1162
|
|
|
1163
|
+
await maybeNotifyUpdate(command, args);
|
|
1164
|
+
|
|
998
1165
|
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
999
1166
|
printRootHelp();
|
|
1000
1167
|
} else if (hasHelpFlag(args)) {
|
|
@@ -1019,7 +1186,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1019
1186
|
}
|
|
1020
1187
|
await createProject(baseUrl, headers, opts);
|
|
1021
1188
|
} else if (command === 'chat') {
|
|
1022
|
-
|
|
1189
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1190
|
+
printChatHelp();
|
|
1191
|
+
process.exit(0);
|
|
1192
|
+
}
|
|
1023
1193
|
let projectId = null;
|
|
1024
1194
|
const chatImages = [];
|
|
1025
1195
|
const chatVideos = [];
|
|
@@ -1027,24 +1197,30 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1027
1197
|
let useStream = false;
|
|
1028
1198
|
let background = false;
|
|
1029
1199
|
let jsonOutput = false;
|
|
1200
|
+
let activeSkill = undefined;
|
|
1030
1201
|
let videoModel = undefined;
|
|
1202
|
+
let videoResolution = undefined;
|
|
1031
1203
|
let preferredModel = undefined;
|
|
1032
1204
|
for (let i = 1; i < args.length; i++) {
|
|
1033
1205
|
if (args[i] === '--project' && args[i + 1]) projectId = args[++i];
|
|
1034
1206
|
else if (args[i] === '--image' && args[i + 1]) chatImages.push(args[++i]);
|
|
1035
1207
|
else if (args[i] === '--video' && args[i + 1]) chatVideos.push(args[++i]);
|
|
1208
|
+
else if (args[i] === '--skill' && args[i + 1]) activeSkill = args[++i];
|
|
1036
1209
|
else if (args[i] === '--stream') useStream = true;
|
|
1037
1210
|
else if (args[i] === '--background' || args[i] === '-b') background = true;
|
|
1038
1211
|
else if (args[i] === '--json') jsonOutput = true;
|
|
1039
1212
|
else if (args[i] === '--video-model' && args[i + 1]) videoModel = args[++i];
|
|
1213
|
+
else if (args[i] === '--video-resolution' && args[i + 1]) videoResolution = args[++i];
|
|
1040
1214
|
else if (args[i] === '--model' && args[i + 1]) preferredModel = args[++i];
|
|
1041
1215
|
else promptParts.push(args[i]);
|
|
1042
1216
|
}
|
|
1043
1217
|
const prompt = promptParts.join(' ');
|
|
1044
1218
|
if (!prompt) {
|
|
1045
|
-
console.error('Usage: makaron chat --project <id|auto> [
|
|
1219
|
+
console.error('Usage: makaron chat --project <id|auto> [options] "your message"');
|
|
1220
|
+
console.error('Run: makaron chat --help');
|
|
1046
1221
|
process.exit(1);
|
|
1047
1222
|
}
|
|
1223
|
+
const { headers, baseUrl } = getAuth();
|
|
1048
1224
|
// Split images into URLs vs local files
|
|
1049
1225
|
const imageUrlList = chatImages.filter(p => p.startsWith('http://') || p.startsWith('https://'));
|
|
1050
1226
|
const imageFileList = chatImages.filter(p => !p.startsWith('http://') && !p.startsWith('https://'));
|
|
@@ -1122,7 +1298,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1122
1298
|
}
|
|
1123
1299
|
|
|
1124
1300
|
// Upload videos to project timeline (via /api/projects/create with videoUrls)
|
|
1125
|
-
let finalPrompt = prompt;
|
|
1301
|
+
let finalPrompt = activeSkill ? `[Active skill: ${activeSkill}]\n${prompt}` : prompt;
|
|
1126
1302
|
if (chatVideos.length > 0) {
|
|
1127
1303
|
// Upload local files via signed URL (no size limit, works with API key auth)
|
|
1128
1304
|
const uploadedVideoUrls = [...prevalidatedVideoUrlList];
|
|
@@ -1166,7 +1342,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1166
1342
|
|
|
1167
1343
|
// Inject hint so Agent knows videos are available
|
|
1168
1344
|
const hint = `[User uploaded ${chatVideos.length === 1 ? 'a video' : `${chatVideos.length} videos`}. Use analyze_video to understand the content.]`;
|
|
1169
|
-
finalPrompt = `${
|
|
1345
|
+
finalPrompt = `${finalPrompt}\n\n${hint}`;
|
|
1170
1346
|
}
|
|
1171
1347
|
|
|
1172
1348
|
if (useStream) {
|
|
@@ -1180,7 +1356,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1180
1356
|
for (const task of results.musicTasks) await pollMusic(baseUrl, headers, task.taskId);
|
|
1181
1357
|
} else {
|
|
1182
1358
|
// Default: fire-and-forget + poll
|
|
1183
|
-
const { runId } = await submitRun(baseUrl, headers, projectId, finalPrompt, { videoModel, preferredModel });
|
|
1359
|
+
const { runId } = await submitRun(baseUrl, headers, projectId, finalPrompt, { videoModel, videoResolution, preferredModel });
|
|
1184
1360
|
if (background) {
|
|
1185
1361
|
// Just print runId and exit
|
|
1186
1362
|
if (jsonOutput) {
|
|
@@ -1311,7 +1487,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1311
1487
|
else promptParts.push(args[i]);
|
|
1312
1488
|
}
|
|
1313
1489
|
editArgs.editPrompt = promptParts.join(' ');
|
|
1314
|
-
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--model gemini|qwen|openai] [--
|
|
1490
|
+
if (!editArgs.editPrompt) { console.error('Usage: makaron edit [--image <file|url>] [--model gemini|qwen|openai] [--ref <file>] [--out <file>] "prompt"'); process.exit(1); }
|
|
1315
1491
|
process.stderr.write('🎨 Generating...\n');
|
|
1316
1492
|
const result = await callMcpTool(baseUrl, headers, 'makaron_edit_image', editArgs);
|
|
1317
1493
|
saveMcpImage(result, outputPath);
|
|
@@ -1347,7 +1523,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1347
1523
|
|
|
1348
1524
|
} else if (sub === 'create') {
|
|
1349
1525
|
const images = [];
|
|
1350
|
-
let script = '', duration = undefined, aspectRatio = undefined, videoModel = undefined, wait = false;
|
|
1526
|
+
let script = '', duration = undefined, aspectRatio = undefined, videoModel = undefined, videoResolution = undefined, wait = false;
|
|
1351
1527
|
let video = null, keepOriginalSound = false;
|
|
1352
1528
|
for (let i = 2; i < args.length; i++) {
|
|
1353
1529
|
if (args[i] === '--image' && args[i + 1]) images.push(args[++i]);
|
|
@@ -1357,6 +1533,8 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1357
1533
|
else if (args[i] === '--duration' && args[i + 1]) duration = Number(args[++i]);
|
|
1358
1534
|
else if (args[i] === '--aspect' && args[i + 1]) aspectRatio = args[++i];
|
|
1359
1535
|
else if (args[i] === '--model' && args[i + 1]) videoModel = args[++i];
|
|
1536
|
+
else if (args[i] === '--video-resolution' && args[i + 1]) videoResolution = args[++i];
|
|
1537
|
+
else if (args[i] === '--resolution' && args[i + 1]) videoResolution = args[++i];
|
|
1360
1538
|
else if (args[i] === '--keep-original-sound') keepOriginalSound = true;
|
|
1361
1539
|
else if (args[i] === '--project') {
|
|
1362
1540
|
console.error('Usage: video create no longer supports --project. Use: makaron chat --project <id> --video <file|url> "your request"');
|
|
@@ -1365,7 +1543,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1365
1543
|
else if (args[i] === '--wait') wait = true;
|
|
1366
1544
|
}
|
|
1367
1545
|
if ((!images.length && !video) || !script) {
|
|
1368
|
-
console.error('Usage: makaron video create --script "..." (--image <url> | --video <public-url>) [--duration 10] [--aspect 9:16] [--model kling|
|
|
1546
|
+
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]');
|
|
1369
1547
|
process.exit(1);
|
|
1370
1548
|
}
|
|
1371
1549
|
|
|
@@ -1376,15 +1554,15 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1376
1554
|
|
|
1377
1555
|
let videoUrl = isHttpUrl(video) ? video : null;
|
|
1378
1556
|
let inputVideoMeta = null;
|
|
1379
|
-
const selectedVideoModel = videoModel || '
|
|
1557
|
+
const selectedVideoModel = videoModel || 'seedance-fast';
|
|
1380
1558
|
if (videoUrl) {
|
|
1381
|
-
process.stderr.write(`📹 Assuming public video URL already matches provider reference limits. Seedance requires ≤${MAX_VIDEO_PROVIDER_REFERENCE_DURATION}s, ≤50MB, sides 300-6000px, frame pixels 409,600-${MAX_VIDEO_FRAME_PIXELS}; Kling requires ≤200MB and ≤2K.\n`);
|
|
1559
|
+
process.stderr.write(`📹 Assuming public video URL already matches provider reference limits. Seedance requires ≤${MAX_VIDEO_PROVIDER_REFERENCE_DURATION}s, ≤50MB, sides 300-6000px, frame pixels 409,600-${MAX_VIDEO_FRAME_PIXELS}; Kling requires ≤200MB and ≤2K. Grok does not support video references.\n`);
|
|
1382
1560
|
}
|
|
1383
1561
|
if (video && !videoUrl) {
|
|
1384
1562
|
const valid = validateVideoFile(video, {
|
|
1385
1563
|
maxDuration: MAX_VIDEO_PROVIDER_REFERENCE_DURATION,
|
|
1386
1564
|
durationTolerance: MAX_VIDEO_PROVIDER_REFERENCE_DURATION_TOLERANCE,
|
|
1387
|
-
...(selectedVideoModel === 'seedance' ? {
|
|
1565
|
+
...(selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast' ? {
|
|
1388
1566
|
minFramePixels: SEEDANCE_MIN_VIDEO_FRAME_PIXELS,
|
|
1389
1567
|
minSide: SEEDANCE_MIN_VIDEO_SIDE,
|
|
1390
1568
|
maxSide: SEEDANCE_MAX_VIDEO_SIDE,
|
|
@@ -1402,12 +1580,11 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1402
1580
|
// Standalone MCP tool (no project timeline write)
|
|
1403
1581
|
process.stderr.write('🎬 Submitting video...\n');
|
|
1404
1582
|
const vArgs = videoUrl
|
|
1405
|
-
? { videoUrl, editPrompt: script, images, videoModel: selectedVideoModel, referType: selectedVideoModel === 'seedance' ? 'feature' : 'base' }
|
|
1406
|
-
: { script, images };
|
|
1583
|
+
? { videoUrl, editPrompt: script, images, videoModel: selectedVideoModel, videoResolution, referType: (selectedVideoModel === 'seedance' || selectedVideoModel === 'seedance-fast') ? 'feature' : 'base' }
|
|
1584
|
+
: { script, images, videoModel: selectedVideoModel, videoResolution };
|
|
1407
1585
|
const effectiveDuration = duration || (inputVideoMeta?.duration ? Math.min(MAX_VIDEO_PROVIDER_REFERENCE_DURATION, Math.round(inputVideoMeta.duration)) : undefined);
|
|
1408
1586
|
if (effectiveDuration) vArgs.duration = effectiveDuration;
|
|
1409
1587
|
if (aspectRatio) vArgs.aspectRatio = aspectRatio;
|
|
1410
|
-
if (videoModel && !videoUrl) vArgs.videoModel = videoModel;
|
|
1411
1588
|
if (keepOriginalSound && videoUrl) vArgs.keepOriginalSound = true;
|
|
1412
1589
|
const result = await callMcpTool(baseUrl, headers, videoUrl ? 'makaron_edit_video' : 'makaron_create_video', vArgs);
|
|
1413
1590
|
const text = result?.content?.find(c => c.type === 'text')?.text;
|
|
@@ -1453,7 +1630,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1453
1630
|
console.log(`Video commands:
|
|
1454
1631
|
video script --image <file> [--image <file>] "direction" Write video script
|
|
1455
1632
|
video create --script "..." --image <url> [--duration 10] Submit video task
|
|
1456
|
-
video create --script "..." --video <public-url> [--model
|
|
1633
|
+
video create --script "..." --video <public-url> [--model seedance-fast|seedance|kling] Edit a video (standalone; Grok does not support video refs)
|
|
1457
1634
|
video status <taskId> Check video status
|
|
1458
1635
|
video status --snapshot <snapshotId> [--wait] Check v2 video snapshot
|
|
1459
1636
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.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
|
|
|
@@ -185,8 +212,8 @@ npx makaron-cli analyze --video input.mp4 "describe the key actions and pacing"
|
|
|
185
212
|
npx makaron-cli video create --script "Shot 1 (5s): <<<image_1>>> ..." --image https://...jpg --duration 5 --model kling
|
|
186
213
|
|
|
187
214
|
# 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
|
|
215
|
+
npx makaron-cli video create --script "make it funny" --video input.mp4 --duration 5 --model seedance-fast
|
|
216
|
+
npx makaron-cli video create --script "make it warmer and cinematic" --video https://example.com/input.mp4 --duration 5 --model seedance --video-resolution 1080p
|
|
190
217
|
|
|
191
218
|
# 4. Check status
|
|
192
219
|
npx makaron-cli video status <taskId>
|
|
@@ -198,9 +225,9 @@ npx makaron-cli video status <taskId>
|
|
|
198
225
|
npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
|
|
199
226
|
```
|
|
200
227
|
|
|
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.
|
|
228
|
+
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.
|
|
202
229
|
|
|
203
|
-
Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance --video` uses the
|
|
230
|
+
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.
|
|
204
231
|
|
|
205
232
|
### `music` — Music generation
|
|
206
233
|
|
|
@@ -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" |
|
|
@@ -303,7 +339,7 @@ send_message "All done!"
|
|
|
303
339
|
- One project = one conversation thread. All history is preserved.
|
|
304
340
|
- One run at a time per project. New message interrupts previous run.
|
|
305
341
|
- Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
|
|
306
|
-
-
|
|
342
|
+
- Most videos take 3-5 minutes; Grok is usually around 30-40 seconds. Use `responses get <runId> --wait --json` for the default customer-service path.
|
|
307
343
|
- Music takes ~60 seconds. Appears in output when done.
|
|
308
344
|
- Images are typically ready in 15-30 seconds.
|
|
309
345
|
- stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
|
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.
|