makaron-cli 0.7.5 → 0.7.7

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/README.md CHANGED
@@ -61,14 +61,14 @@ Share the `claim_url` with a human. They log in and the API key gets linked to t
61
61
  # One-shot: create project + upload image + submit prompt — all in one command
62
62
  RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinematic and create a 5s video")
63
63
 
64
- # Watch until all artifacts are ready
65
- npx makaron-cli responses watch $RUN_ID --jsonl
64
+ # Wait for the final customer-ready result
65
+ npx makaron-cli responses get $RUN_ID --wait --json
66
66
  ```
67
67
 
68
68
  Or with an existing project:
69
69
  ```bash
70
70
  RUN_ID=$(npx makaron-cli chat --project $PROJECT_ID -b "make a 5s video")
71
- npx makaron-cli responses watch $RUN_ID --jsonl
71
+ npx makaron-cli responses get $RUN_ID --wait --json
72
72
  ```
73
73
 
74
74
  ## Primary: `chat` (Agent-driven creative work)
@@ -110,8 +110,8 @@ npx makaron-cli chat --project <id> --video party.mp4 --image kid.jpg -b "make t
110
110
  npx makaron-cli chat --project <id> --video clip1.mp4 --video clip2.mp4 -b "splice these into one seamless video"
111
111
  ```
112
112
 
113
- Video files are uploaded via signed URL. CLI local video uploads follow the same compatibility contract as the normal frontend flow: `.mp4`, `.mov`, or `.webm`, max 200MB, max 15s, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail.
114
- The agent understands video content natively — it can analyze scenes, edit, extend, and compose videos. Seedance video-reference editing is supported for <=15s videos that meet the same upload limits; Kling remains the base/direct edit path.
113
+ Video files are uploaded via signed URL. CLI local video uploads follow the same compatibility contract as the normal frontend flow: `.mp4`, `.mov`, or `.webm`, max 200MB, target max 15s with 0.5s metadata tolerance, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail.
114
+ The agent understands video content natively — it can analyze scenes, edit, extend, and compose videos. Seedance video-reference editing is supported for ~15s videos that meet the same upload limits; Kling remains the base/direct edit path.
115
115
  Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct `video create` is standalone and does not write timeline entries.
116
116
 
117
117
  ### Check status (single query)
@@ -120,7 +120,7 @@ Use `chat --project <id|auto> --video ...` for any project/timeline video work.
120
120
  npx makaron-cli responses get <runId> --json
121
121
  ```
122
122
 
123
- ### Watch until done (streaming events)
123
+ ### Advanced: stream incremental events
124
124
 
125
125
  ```bash
126
126
  npx makaron-cli responses watch <runId> --jsonl
@@ -198,7 +198,7 @@ npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
198
198
 
199
199
  Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration 3|5|7|10|15`, `--aspect 9:16|16:9|1:1`, `--model kling|seedance`
200
200
 
201
- Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance --video` uses the Seedance video-reference path and requires <=15s, <=1080p input.
201
+ 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, <=1080p input. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s.
202
202
 
203
203
  ### `music` — Music generation
204
204
 
@@ -278,38 +278,33 @@ RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinem
278
278
  PROJECT_URL=$(npx makaron-cli responses get $RUN_ID --pick project_url)
279
279
  send_message "Project created: $PROJECT_URL"
280
280
 
281
- # 4. Watch and send each artifact as it appears
282
- npx makaron-cli responses watch $RUN_ID --jsonl | while read -r line; do
283
- EVENT=$(echo "$line" | jq -r '.event')
284
- TYPE=$(echo "$line" | jq -r '.item.type // empty')
285
- URL=$(echo "$line" | jq -r '.item.url // empty')
286
- STATUS=$(echo "$line" | jq -r '.item.status // empty')
287
-
288
- if [ "$EVENT" = "output.added" ] && [ "$TYPE" = "image" ]; then
289
- # Send image immediately as media (not just link)
290
- send_image "$URL"
291
- elif [ "$EVENT" = "output.updated" ] && [ "$TYPE" = "video" ] && [ "$STATUS" = "completed" ]; then
292
- # Video ready — send as media
293
- send_video "$URL"
294
- elif [ "$EVENT" = "done" ]; then
295
- send_message "All done!"
296
- fi
281
+ # 4. Wait for the final customer-ready result
282
+ RESULT=$(npx makaron-cli responses get $RUN_ID --wait --json)
283
+ IMAGE_URLS=$(echo "$RESULT" | jq -r '[.result.images[]?.imageUrl, .output[]? | select(.type == "image") | .url] | map(select(. != null)) | unique | .[]')
284
+ VIDEO_URLS=$(echo "$RESULT" | jq -r '[.result.videos[]?.videoUrl, .output[]? | select(.type == "video") | .url] | map(select(. != null)) | unique | .[]')
285
+
286
+ for URL in $IMAGE_URLS; do
287
+ send_image "$URL"
288
+ done
289
+ for URL in $VIDEO_URLS; do
290
+ send_video "$URL"
297
291
  done
292
+ send_message "All done!"
298
293
  ```
299
294
 
300
295
  **Key principles for service agents:**
301
- - **Proactive, not reactive**: Don't wait for the full run to finish. Send progress messages and artifacts as they appear.
296
+ - **Proactive, not silent**: Acknowledge immediately, send the project link early, then send the final customer-ready media when the run completes.
302
297
  - **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.
303
298
  - **Immediate acknowledgment**: Reply within 1 second of receiving user request. Don't make users wait for project creation.
304
299
  - **Project link early**: Send the project URL right after creation so users can check anytime.
305
- - **Stream artifacts**: Use `watch --jsonl` to push each artifact the moment it's ready. An image at 15s should reach the user at 15s, not after the video finishes at 5 minutes.
300
+ - **Use `get --wait --json` as the default service path**: reserve `watch --jsonl` for advanced streaming or debugging integrations that explicitly need incremental events.
306
301
 
307
302
  ## Important Notes
308
303
 
309
304
  - One project = one conversation thread. All history is preserved.
310
305
  - One run at a time per project. New message interrupts previous run.
311
306
  - Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
312
- - Videos take 2-5 minutes to render. Use `watch` to get URL when ready.
307
+ - Videos take 2-5 minutes to render. Use `responses get <runId> --wait --json` for the default customer-service path.
313
308
  - Music takes ~60 seconds. Appears in output when done.
314
309
  - Images are typically ready in 15-30 seconds.
315
310
  - stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
package/SKILL.md CHANGED
@@ -50,14 +50,14 @@ Verify: `npx makaron-cli list` should show projects.
50
50
  # One-shot: create project + upload image + submit prompt — all in one command
51
51
  RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinematic and create a 5s video")
52
52
 
53
- # Watch until all artifacts are ready
54
- npx makaron-cli responses watch $RUN_ID --jsonl
53
+ # Wait for the final customer-ready result
54
+ npx makaron-cli responses get $RUN_ID --wait --json
55
55
  ```
56
56
 
57
57
  Or with an existing project:
58
58
  ```bash
59
59
  RUN_ID=$(npx makaron-cli chat --project $PROJECT_ID -b "make a 5s video")
60
- npx makaron-cli responses watch $RUN_ID --jsonl
60
+ npx makaron-cli responses get $RUN_ID --wait --json
61
61
  ```
62
62
 
63
63
  ## Primary: `chat` (Agent-driven creative work)
@@ -102,7 +102,7 @@ npx makaron-cli chat --project <id> --video clip1.mp4 --video clip2.mp4 -b "comb
102
102
  npx makaron-cli chat --project auto --video https://example.com/dance.mp4 -b "extend this to 15 seconds"
103
103
  ```
104
104
 
105
- Supported formats: MP4, MOV, WebM. CLI local video uploads follow the same compatibility contract as the normal frontend flow: max 200MB, max 15s, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail. 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 supported for <=15s videos that meet these upload limits; Kling remains the base/direct edit path.
105
+ Supported formats: MP4, MOV, WebM. CLI local video uploads follow the same compatibility contract as the normal frontend flow: max 200MB, target max 15s with 0.5s metadata tolerance, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail. 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 supported for ~15s videos that meet these upload limits; Kling remains the base/direct edit path.
106
106
 
107
107
  Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct video commands are standalone raw-tool calls.
108
108
 
@@ -112,7 +112,7 @@ Use `chat --project <id|auto> --video ...` for any project/timeline video work.
112
112
  npx makaron-cli responses get <runId> --json
113
113
  ```
114
114
 
115
- ### Watch until done (streaming events)
115
+ ### Advanced: stream incremental events
116
116
 
117
117
  ```bash
118
118
  npx makaron-cli responses watch <runId> --jsonl
@@ -190,7 +190,7 @@ npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
190
190
 
191
191
  Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration 3|5|7|10|15`, `--aspect 9:16|16:9|1:1`, `--model kling|seedance`
192
192
 
193
- Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance --video` uses the Seedance video-reference path and requires <=15s, <=1080p input.
193
+ 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, <=1080p input. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s.
194
194
 
195
195
  ### `music` — Music generation
196
196
 
@@ -267,38 +267,33 @@ RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinem
267
267
  PROJECT_URL=$(npx makaron-cli responses get $RUN_ID --pick project_url)
268
268
  send_message "Project created: $PROJECT_URL"
269
269
 
270
- # 4. Watch and send each artifact as it appears
271
- npx makaron-cli responses watch $RUN_ID --jsonl | while read -r line; do
272
- EVENT=$(echo "$line" | jq -r '.event')
273
- TYPE=$(echo "$line" | jq -r '.item.type // empty')
274
- URL=$(echo "$line" | jq -r '.item.url // empty')
275
- STATUS=$(echo "$line" | jq -r '.item.status // empty')
276
-
277
- if [ "$EVENT" = "output.added" ] && [ "$TYPE" = "image" ]; then
278
- # Send image immediately as media (not just link)
279
- send_image "$URL"
280
- elif [ "$EVENT" = "output.updated" ] && [ "$TYPE" = "video" ] && [ "$STATUS" = "completed" ]; then
281
- # Video ready — send as media
282
- send_video "$URL"
283
- elif [ "$EVENT" = "done" ]; then
284
- send_message "All done!"
285
- fi
270
+ # 4. Wait for the final customer-ready result
271
+ RESULT=$(npx makaron-cli responses get $RUN_ID --wait --json)
272
+ IMAGE_URLS=$(echo "$RESULT" | jq -r '[.result.images[]?.imageUrl, .output[]? | select(.type == "image") | .url] | map(select(. != null)) | unique | .[]')
273
+ VIDEO_URLS=$(echo "$RESULT" | jq -r '[.result.videos[]?.videoUrl, .output[]? | select(.type == "video") | .url] | map(select(. != null)) | unique | .[]')
274
+
275
+ for URL in $IMAGE_URLS; do
276
+ send_image "$URL"
277
+ done
278
+ for URL in $VIDEO_URLS; do
279
+ send_video "$URL"
286
280
  done
281
+ send_message "All done!"
287
282
  ```
288
283
 
289
284
  **Key principles for service agents:**
290
- - **Proactive, not reactive**: Don't wait for the full run to finish. Send progress messages and artifacts as they appear.
285
+ - **Proactive, not silent**: Acknowledge immediately, send the project link early, then send the final customer-ready media when the run completes.
291
286
  - **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.
292
287
  - **Immediate acknowledgment**: Reply within 1 second of receiving user request. Don't make users wait for project creation.
293
288
  - **Project link early**: Send the project URL right after creation so users can check anytime.
294
- - **Stream artifacts**: Use `watch --jsonl` to push each artifact the moment it's ready. An image at 15s should reach the user at 15s, not after the video finishes at 5 minutes.
289
+ - **Use `get --wait --json` as the default service path**: reserve `watch --jsonl` for advanced streaming or debugging integrations that explicitly need incremental events.
295
290
 
296
291
  ## Important Notes
297
292
 
298
293
  - One project = one conversation thread. All history is preserved.
299
294
  - One run at a time per project. New message interrupts previous run.
300
295
  - Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
301
- - Videos take 2-5 minutes to render. Use `watch` to get URL when ready.
296
+ - Videos take 2-5 minutes to render. Use `responses get <runId> --wait --json` for the default customer-service path.
302
297
  - Music takes ~60 seconds. Appears in output when done.
303
298
  - Images are typically ready in 15-30 seconds.
304
299
  - stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.
package/bin/makaron.mjs CHANGED
@@ -29,8 +29,23 @@ const SUPABASE_ANON_KEY = 'sb_publishable_FJFN2YYaWaQjABUKLqxQcA_fhxPLFDY';
29
29
 
30
30
  const MAX_VIDEO_FILE_SIZE = 200 * 1024 * 1024;
31
31
  const MAX_VIDEO_DURATION = 15;
32
+ const MAX_VIDEO_DURATION_TOLERANCE = 0.5;
32
33
  const MAX_VIDEO_FRAME_PIXELS = 2_086_876;
33
34
 
35
+ function getCliVersion() {
36
+ try {
37
+ const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
38
+ return pkg.version || '0.0.0';
39
+ } catch {
40
+ return '0.0.0';
41
+ }
42
+ }
43
+
44
+ function formatSeconds(seconds) {
45
+ if (!Number.isFinite(seconds)) return String(seconds);
46
+ return Number.isInteger(seconds) ? String(seconds) : seconds.toFixed(1).replace(/\.0$/, '');
47
+ }
48
+
34
49
  // ─── Auth ────────────────────────────────────────────────────────────────────
35
50
 
36
51
  function loadAuth() {
@@ -403,7 +418,7 @@ function applyPick(data, field) {
403
418
  case 'design_urls': return (data.output || []).filter(o => o.type === 'design' && o.url).map(o => o.url);
404
419
  case 'first_music_url': return data.output?.find(o => o.type === 'music' && o.url)?.url || null;
405
420
  case 'music_urls': return (data.output || []).filter(o => o.type === 'music' && o.url).map(o => o.url);
406
- case 'project_url': return data.project_url || null;
421
+ case 'project_url': return data.project_url || data.projectUrl || null;
407
422
  case 'output': return data.output || [];
408
423
  case 'text': return data.output?.find(o => o.type === 'text')?.content || null;
409
424
  case 'status': return data.status;
@@ -735,8 +750,8 @@ function validateVideoFile(videoPath) {
735
750
  if (!meta) {
736
751
  return { ok: false, error: 'Cannot read video duration/resolution. Install ffmpeg/ffprobe or use the normal frontend upload flow.' };
737
752
  }
738
- if (meta.duration > MAX_VIDEO_DURATION) {
739
- return { ok: false, error: `Video too long: ${Math.round(meta.duration)}s (max ${MAX_VIDEO_DURATION}s)` };
753
+ if (meta.duration > MAX_VIDEO_DURATION + MAX_VIDEO_DURATION_TOLERANCE) {
754
+ return { ok: false, error: `Video too long: ${formatSeconds(meta.duration)}s (max ${MAX_VIDEO_DURATION}s, with ${MAX_VIDEO_DURATION_TOLERANCE}s metadata tolerance)` };
740
755
  }
741
756
  if (meta.width * meta.height > MAX_VIDEO_FRAME_PIXELS) {
742
757
  return { ok: false, error: `Video resolution too high: ${meta.width}x${meta.height} (${meta.width * meta.height} px). Max is <=1080p (${MAX_VIDEO_FRAME_PIXELS} px). Re-upload through the frontend to transcode, or export a smaller video.` };
@@ -807,7 +822,9 @@ async function analyzeVideoCli(baseUrl, headers, rawVideo, questionParts) {
807
822
  const args = process.argv.slice(2);
808
823
  const command = args[0];
809
824
 
810
- if (command === 'login') {
825
+ if (command === '--version' || command === '-v' || command === 'version') {
826
+ console.log(getCliVersion());
827
+ } else if (command === 'login') {
811
828
  await login();
812
829
  } else if (command === 'create') {
813
830
  const { headers, baseUrl } = getAuth();
@@ -1190,14 +1207,17 @@ if (command === 'login') {
1190
1207
  const vArgs = videoUrl
1191
1208
  ? { videoUrl, editPrompt: script, images, videoModel: videoModel || 'kling', referType: (videoModel || 'kling') === 'seedance' ? 'feature' : 'base' }
1192
1209
  : { script, images };
1193
- const effectiveDuration = duration || (inputVideoMeta?.duration ? Math.round(inputVideoMeta.duration) : undefined);
1210
+ const effectiveDuration = duration || (inputVideoMeta?.duration ? Math.min(MAX_VIDEO_DURATION, Math.round(inputVideoMeta.duration)) : undefined);
1194
1211
  if (effectiveDuration) vArgs.duration = effectiveDuration;
1195
1212
  if (aspectRatio) vArgs.aspectRatio = aspectRatio;
1196
1213
  if (videoModel && !videoUrl) vArgs.videoModel = videoModel;
1197
1214
  if (keepOriginalSound && videoUrl) vArgs.keepOriginalSound = true;
1198
1215
  const result = await callMcpTool(baseUrl, headers, videoUrl ? 'makaron_edit_video' : 'makaron_create_video', vArgs);
1199
1216
  const text = result?.content?.find(c => c.type === 'text')?.text;
1200
- if (text) console.log(text);
1217
+ if (text) {
1218
+ console.log(text);
1219
+ if (!text.includes('Task ID:')) process.exit(1);
1220
+ }
1201
1221
 
1202
1222
  } else if (sub === 'status') {
1203
1223
  let taskId = null, snapshotId = null, wait = false;
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "makaron-cli",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Talk to Makaron Agent from the terminal — create projects, edit images, generate videos",
5
5
  "type": "module",
6
+ "scripts": {
7
+ "test": "node test/smoke.mjs",
8
+ "test:smoke": "node test/smoke.mjs",
9
+ "test:live": "MAKARON_LIVE=1 node test/live-smoke.mjs"
10
+ },
6
11
  "bin": {
7
12
  "makaron": "./bin/makaron.mjs"
8
13
  },
@@ -50,14 +50,14 @@ Verify: `npx makaron-cli list` should show projects.
50
50
  # One-shot: create project + upload image + submit prompt — all in one command
51
51
  RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinematic and create a 5s video")
52
52
 
53
- # Watch until all artifacts are ready
54
- npx makaron-cli responses watch $RUN_ID --jsonl
53
+ # Wait for the final customer-ready result
54
+ npx makaron-cli responses get $RUN_ID --wait --json
55
55
  ```
56
56
 
57
57
  Or with an existing project:
58
58
  ```bash
59
59
  RUN_ID=$(npx makaron-cli chat --project $PROJECT_ID -b "make a 5s video")
60
- npx makaron-cli responses watch $RUN_ID --jsonl
60
+ npx makaron-cli responses get $RUN_ID --wait --json
61
61
  ```
62
62
 
63
63
  ## Primary: `chat` (Agent-driven creative work)
@@ -102,7 +102,7 @@ npx makaron-cli chat --project <id> --video clip1.mp4 --video clip2.mp4 -b "comb
102
102
  npx makaron-cli chat --project auto --video https://example.com/dance.mp4 -b "extend this to 15 seconds"
103
103
  ```
104
104
 
105
- Supported formats: MP4, MOV, WebM. CLI local video uploads follow the same compatibility contract as the normal frontend flow: max 200MB, max 15s, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail. 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 supported for <=15s videos that meet these upload limits; Kling remains the base/direct edit path.
105
+ Supported formats: MP4, MOV, WebM. CLI local video uploads follow the same compatibility contract as the normal frontend flow: max 200MB, target max 15s with 0.5s metadata tolerance, and <=1080p / 2,086,876 frame pixels. The frontend can transcode oversized videos; the CLI rejects them so later Seedance editing does not fail. 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 supported for ~15s videos that meet these upload limits; Kling remains the base/direct edit path.
106
106
 
107
107
  Use `chat --project <id|auto> --video ...` for any project/timeline video work. Direct video commands are standalone raw-tool calls.
108
108
 
@@ -112,7 +112,7 @@ Use `chat --project <id|auto> --video ...` for any project/timeline video work.
112
112
  npx makaron-cli responses get <runId> --json
113
113
  ```
114
114
 
115
- ### Watch until done (streaming events)
115
+ ### Advanced: stream incremental events
116
116
 
117
117
  ```bash
118
118
  npx makaron-cli responses watch <runId> --jsonl
@@ -190,7 +190,7 @@ npx makaron-cli chat --project <id|auto> --video input.mp4 -b "make it funny"
190
190
 
191
191
  Options for `video create`: `--script "..."`, `--script-file <path>`, `--image <url>` (repeatable, up to 7), `--video <file|url>`, `--duration 3|5|7|10|15`, `--aspect 9:16|16:9|1:1`, `--model kling|seedance`
192
192
 
193
- Video edit model behavior: `--model kling --video` uses Kling base/direct edit internally; `--model seedance --video` uses the Seedance video-reference path and requires <=15s, <=1080p input.
193
+ 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, <=1080p input. Tiny metadata padding up to 15.5s is accepted and output duration is clamped to 15s.
194
194
 
195
195
  ### `music` — Music generation
196
196
 
@@ -267,38 +267,33 @@ RUN_ID=$(npx makaron-cli chat --project auto --image photo.jpg -b "make it cinem
267
267
  PROJECT_URL=$(npx makaron-cli responses get $RUN_ID --pick project_url)
268
268
  send_message "Project created: $PROJECT_URL"
269
269
 
270
- # 4. Watch and send each artifact as it appears
271
- npx makaron-cli responses watch $RUN_ID --jsonl | while read -r line; do
272
- EVENT=$(echo "$line" | jq -r '.event')
273
- TYPE=$(echo "$line" | jq -r '.item.type // empty')
274
- URL=$(echo "$line" | jq -r '.item.url // empty')
275
- STATUS=$(echo "$line" | jq -r '.item.status // empty')
276
-
277
- if [ "$EVENT" = "output.added" ] && [ "$TYPE" = "image" ]; then
278
- # Send image immediately as media (not just link)
279
- send_image "$URL"
280
- elif [ "$EVENT" = "output.updated" ] && [ "$TYPE" = "video" ] && [ "$STATUS" = "completed" ]; then
281
- # Video ready — send as media
282
- send_video "$URL"
283
- elif [ "$EVENT" = "done" ]; then
284
- send_message "All done!"
285
- fi
270
+ # 4. Wait for the final customer-ready result
271
+ RESULT=$(npx makaron-cli responses get $RUN_ID --wait --json)
272
+ IMAGE_URLS=$(echo "$RESULT" | jq -r '[.result.images[]?.imageUrl, .output[]? | select(.type == "image") | .url] | map(select(. != null)) | unique | .[]')
273
+ VIDEO_URLS=$(echo "$RESULT" | jq -r '[.result.videos[]?.videoUrl, .output[]? | select(.type == "video") | .url] | map(select(. != null)) | unique | .[]')
274
+
275
+ for URL in $IMAGE_URLS; do
276
+ send_image "$URL"
277
+ done
278
+ for URL in $VIDEO_URLS; do
279
+ send_video "$URL"
286
280
  done
281
+ send_message "All done!"
287
282
  ```
288
283
 
289
284
  **Key principles for service agents:**
290
- - **Proactive, not reactive**: Don't wait for the full run to finish. Send progress messages and artifacts as they appear.
285
+ - **Proactive, not silent**: Acknowledge immediately, send the project link early, then send the final customer-ready media when the run completes.
291
286
  - **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.
292
287
  - **Immediate acknowledgment**: Reply within 1 second of receiving user request. Don't make users wait for project creation.
293
288
  - **Project link early**: Send the project URL right after creation so users can check anytime.
294
- - **Stream artifacts**: Use `watch --jsonl` to push each artifact the moment it's ready. An image at 15s should reach the user at 15s, not after the video finishes at 5 minutes.
289
+ - **Use `get --wait --json` as the default service path**: reserve `watch --jsonl` for advanced streaming or debugging integrations that explicitly need incremental events.
295
290
 
296
291
  ## Important Notes
297
292
 
298
293
  - One project = one conversation thread. All history is preserved.
299
294
  - One run at a time per project. New message interrupts previous run.
300
295
  - Multi-image: `create --image a.jpg --image b.jpg` or `chat --image ref.jpg`.
301
- - Videos take 2-5 minutes to render. Use `watch` to get URL when ready.
296
+ - Videos take 2-5 minutes to render. Use `responses get <runId> --wait --json` for the default customer-service path.
302
297
  - Music takes ~60 seconds. Appears in output when done.
303
298
  - Images are typically ready in 15-30 seconds.
304
299
  - stdout is always machine-readable JSON/text. Human-friendly logs go to stderr.