@cueframe/kernel 0.1.2 → 0.1.4

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.
Files changed (126) hide show
  1. package/dist/_members/authoring/agent/errors.d.ts +8 -0
  2. package/dist/_members/authoring/index.d.ts +1 -1
  3. package/dist/_members/authoring/motion/materializeMotionPresetOps.d.ts +4 -0
  4. package/dist/_members/authoring/prompts/index.d.ts +0 -1
  5. package/dist/_members/authoring/types.d.ts +1 -1
  6. package/dist/_members/cloud-import/CloudImportService.d.ts +3 -4
  7. package/dist/_members/cloud-import/ImportProvider.d.ts +3 -7
  8. package/dist/_members/cloud-import/cloudConfig.d.ts +0 -6
  9. package/dist/_members/cloud-import/index.d.ts +2 -4
  10. package/dist/_members/composition/graphics-plan/schemas.d.ts +20 -20
  11. package/dist/_members/composition/primitive-catalog/projection.d.ts +2 -1
  12. package/dist/_members/composition/projection/behind-readiness.d.ts +4 -2
  13. package/dist/_members/composition/validators/brandKit.d.ts +54 -94
  14. package/dist/_members/composition/validators/composePlan.d.ts +52 -52
  15. package/dist/_members/composition/validators/composition.d.ts +213 -253
  16. package/dist/_members/composition/validators/font.d.ts +2 -2
  17. package/dist/_members/composition/validators/index.d.ts +1 -0
  18. package/dist/_members/composition/validators/opaqueId.d.ts +13 -0
  19. package/dist/_members/composition/validators/project.d.ts +11 -15
  20. package/dist/_members/composition/validators/render.d.ts +372 -534
  21. package/dist/_members/composition/validators/session.d.ts +19 -39
  22. package/dist/_members/composition/validators/webhook.d.ts +8 -16
  23. package/dist/_members/composition-ops/index.d.ts +192 -228
  24. package/dist/_members/director/ai-sdk/messages.d.ts +2 -2
  25. package/dist/_members/director/domain/chat.d.ts +4 -4
  26. package/dist/_members/director/testing/contract.d.ts +1 -1
  27. package/dist/_members/errors/registry.d.ts +115 -1
  28. package/dist/_members/mcp/adapter.d.ts +19 -0
  29. package/dist/_members/mcp/core.d.ts +1 -1
  30. package/dist/_members/mcp/curation.d.ts +4 -0
  31. package/dist/_members/mcp/generated/harness.d.ts +1 -1
  32. package/dist/_members/mcp/generated/operations.d.ts +12 -0
  33. package/dist/_members/mcp/wait.d.ts +1 -1
  34. package/dist/_members/media-model/api.d.ts +53 -109
  35. package/dist/_members/media-model/generation.d.ts +2 -2
  36. package/dist/_members/media-model/index.d.ts +1 -0
  37. package/dist/_members/media-model/opaqueId.d.ts +10 -0
  38. package/dist/_members/render-harness/localRender.d.ts +3 -0
  39. package/dist/_members/render-harness/localRender.d.ts.map +1 -1
  40. package/dist/_members/render-harness/remotion-runtime.d.ts +53 -0
  41. package/dist/authoring/build-tools.js +6 -6
  42. package/dist/authoring/context.js +4 -4
  43. package/dist/authoring/prompts.js +1 -5
  44. package/dist/authoring/tools.js +5 -5
  45. package/dist/authoring.js +40 -27
  46. package/dist/chunk-2SNY75AR.js +498 -0
  47. package/dist/{chunk-XQ72DZKJ.js → chunk-7TQCR7AB.js} +1 -1
  48. package/dist/{chunk-QETYXKQQ.js → chunk-7V3F5HO4.js} +97 -14
  49. package/dist/{chunk-BZZTVOGG.js → chunk-D2EGO543.js} +5 -5
  50. package/dist/{chunk-ZPLJ24OV.js → chunk-D6S3ZKIY.js} +1 -1
  51. package/dist/{chunk-K2IUBCND.js → chunk-HFC3MKXA.js} +0 -51
  52. package/dist/{chunk-ICSZF37W.js → chunk-JRIPQ7DN.js} +1 -1
  53. package/dist/{chunk-TFGKUWHY.js → chunk-JTVFIN6H.js} +15 -19
  54. package/dist/{chunk-DCVJWGIA.js → chunk-JY26PIRP.js} +2 -2
  55. package/dist/{chunk-DWLNPNC4.js → chunk-LSP4HN5N.js} +1 -1
  56. package/dist/{chunk-AO744WIK.js → chunk-PJ4R4N4Q.js} +123 -38
  57. package/dist/{chunk-VFMW3JUY.js → chunk-QSDFTYKV.js} +1 -1
  58. package/dist/{chunk-LLUW26BS.js → chunk-R5BMJ2NX.js} +38 -2
  59. package/dist/{chunk-W3SIWT7J.js → chunk-RQ2G4DXI.js} +406 -174
  60. package/dist/{chunk-VHF66LCQ.js → chunk-RXCEPCAQ.js} +102 -41
  61. package/dist/{chunk-LJ5W4ZBU.js → chunk-TLVPDT4R.js} +1 -1
  62. package/dist/{chunk-PIURX6IZ.js → chunk-WTT3GGCA.js} +9 -4
  63. package/dist/{chunk-CAJQ7H5A.js → chunk-YE3F4LNJ.js} +17 -17
  64. package/dist/{chunk-TD347SSX.js → chunk-YXEZ75MB.js} +31 -20
  65. package/dist/{chunk-TPA6PYN2.js → chunk-ZBRPF6GV.js} +25 -10
  66. package/dist/cloud-import.js +20 -116
  67. package/dist/compose/renderer.js +17 -17
  68. package/dist/compose.js +18 -18
  69. package/dist/composition/graphics-plan.js +1 -1
  70. package/dist/composition/ops.js +3 -3
  71. package/dist/composition/primitive-catalog.js +1 -1
  72. package/dist/composition/projection.js +2 -2
  73. package/dist/composition/validators.js +4 -2
  74. package/dist/composition-ops.js +6 -6
  75. package/dist/composition.js +6 -4
  76. package/dist/{context-JLLU3MYD.js → context-XWNT6QZH.js} +4 -4
  77. package/dist/core/render.js +3 -3
  78. package/dist/core/select.js +2 -2
  79. package/dist/core.js +3 -3
  80. package/dist/director/ai-sdk.js +3 -3
  81. package/dist/director/domain.js +2 -2
  82. package/dist/director.js +3 -3
  83. package/dist/errors.js +1 -1
  84. package/dist/mcp/adapter.js +59 -22
  85. package/dist/mcp/core.js +1 -1
  86. package/dist/mcp/curation.js +5 -1
  87. package/dist/mcp/server.js +4 -4
  88. package/dist/mcp.js +4 -4
  89. package/dist/media-model/media-kind.js +98 -9
  90. package/dist/media-model/testing.js +6 -6
  91. package/dist/media-model.js +83 -77
  92. package/dist/nle-export.js +18 -18
  93. package/dist/primitives/backgrounds.js +2 -2
  94. package/dist/primitives/captions.js +3 -3
  95. package/dist/primitives/effects.js +2 -2
  96. package/dist/primitives/hero-text.js +2 -2
  97. package/dist/primitives/layouts.js +2 -2
  98. package/dist/primitives/lib/index.js +12 -12
  99. package/dist/primitives/lib.js +12 -12
  100. package/dist/primitives/scenes.js +2 -2
  101. package/dist/primitives/text.js +2 -2
  102. package/dist/primitives/ui-blocks.js +2 -2
  103. package/dist/primitives.js +19 -19
  104. package/dist/render-harness.js +4 -2
  105. package/package.json +13 -37
  106. package/dist/_members/authoring/prompts/designReviewerPrompt.d.ts +0 -2
  107. package/dist/_members/cloud-import/MediaItemPreprocessor.d.ts +0 -18
  108. package/dist/_members/cloud-import/multipartUpload.d.ts +0 -12
  109. package/dist/_members/convex-api/api.d.ts +0 -2
  110. package/dist/_members/convex-api/dataModel.d.ts +0 -4
  111. package/dist/chunk-6IU2UQI5.js +0 -107
  112. package/dist/chunk-EP2Y6M2J.js +0 -64
  113. package/dist/chunk-WZH57M53.js +0 -494
  114. package/dist/cloud-import/multipart.d.ts +0 -1
  115. package/dist/cloud-import/multipart.js +0 -8
  116. package/dist/convex-api/dataModel.d.ts +0 -1
  117. package/dist/convex-api/dataModel.js +0 -0
  118. package/dist/convex-api.d.ts +0 -1
  119. package/dist/convex-api.js +0 -8
  120. package/dist/{chunk-RP4SXXLJ.js → chunk-3PM6VICZ.js} +3 -3
  121. package/dist/{chunk-UQSOS726.js → chunk-6ABIXGLO.js} +4 -4
  122. package/dist/{chunk-SAMQUUO5.js → chunk-BIBYZJL3.js} +3 -3
  123. package/dist/{chunk-GMD33ZD7.js → chunk-O7GNE4BQ.js} +3 -3
  124. package/dist/{chunk-BKHGL4MB.js → chunk-THJAY7QS.js} +4 -4
  125. package/dist/{chunk-DYZE7JZA.js → chunk-TMIBBD5E.js} +3 -3
  126. package/dist/{chunk-G5BFI32U.js → chunk-XATRRDVG.js} +3 -3
@@ -3,6 +3,10 @@ import {
3
3
  buildEasedZooms,
4
4
  buildPannedCenters
5
5
  } from "./chunk-QH3YI3ND.js";
6
+ import {
7
+ flattenCompoundClips,
8
+ hasCompoundClips
9
+ } from "./chunk-23HFEKV7.js";
6
10
  import {
7
11
  DOMINANCE_WEIGHTS,
8
12
  ENTER_SEC,
@@ -20,11 +24,7 @@ import {
20
24
  scoreAndRank,
21
25
  segmentShots,
22
26
  stabilizeSelectionHysteresis
23
- } from "./chunk-XQ72DZKJ.js";
24
- import {
25
- flattenCompoundClips,
26
- hasCompoundClips
27
- } from "./chunk-23HFEKV7.js";
27
+ } from "./chunk-7TQCR7AB.js";
28
28
  import {
29
29
  compositionHasVo,
30
30
  roleDefaultGainDb
@@ -36,7 +36,7 @@ import {
36
36
  import {
37
37
  CueframeError,
38
38
  encodeError
39
- } from "./chunk-LLUW26BS.js";
39
+ } from "./chunk-R5BMJ2NX.js";
40
40
 
41
41
  // ../execution/core/src/render/emphasis.ts
42
42
  function buildEmphasisSet(emphasisWords) {
@@ -178,6 +178,9 @@ function resolveBookendTimeline(brandKit, bodyFrames, fps) {
178
178
  }
179
179
 
180
180
  // ../execution/core/src/render/compositionRender.ts
181
+ function renderInputError(code, message, locator) {
182
+ return new CueframeError(code, message, void 0, locator);
183
+ }
181
184
  function projectClipEffects(clip, renderClipId) {
182
185
  const effects = clip.effects;
183
186
  if (!effects || effects.length === 0) return [];
@@ -217,53 +220,81 @@ function compositionFormatDimensions(format) {
217
220
  }
218
221
  function validateComposition(raw) {
219
222
  if (!raw || typeof raw !== "object") {
220
- throw new Error("composition: expected object, got " + typeof raw);
223
+ throw renderInputError("invalid_composition", "composition: expected object, got " + typeof raw, {
224
+ compositionPath: "composition"
225
+ });
221
226
  }
222
227
  const obj = raw;
223
228
  if (obj.v !== 1) {
224
- throw new Error("composition.v: expected literal 1");
229
+ throw renderInputError("invalid_composition", "composition.v: expected literal 1", {
230
+ compositionPath: "composition.v"
231
+ });
225
232
  }
226
233
  const fmt = obj.format;
227
234
  if (!fmt || typeof fmt.aspectRatio !== "string") {
228
- throw new Error("composition.format.aspectRatio: required string");
235
+ throw renderInputError("invalid_composition", "composition.format.aspectRatio: required string", {
236
+ compositionPath: "composition.format.aspectRatio"
237
+ });
229
238
  }
230
239
  if (!Array.isArray(obj.tracks)) {
231
- throw new Error("composition.tracks: expected array");
240
+ throw renderInputError("invalid_composition", "composition.tracks: expected array", {
241
+ compositionPath: "composition.tracks"
242
+ });
232
243
  }
233
244
  for (let i = 0; i < obj.tracks.length; i++) {
234
245
  const t = obj.tracks[i];
235
246
  if (!t || typeof t !== "object") {
236
- throw new Error(`composition.tracks[${i}]: expected object`);
247
+ throw renderInputError("invalid_composition", `composition.tracks[${i}]: expected object`, {
248
+ compositionPath: `composition.tracks[${i}]`
249
+ });
237
250
  }
238
251
  if (typeof t.id !== "string") {
239
- throw new Error(`composition.tracks[${i}].id: expected string`);
252
+ throw renderInputError("invalid_composition", `composition.tracks[${i}].id: expected string`, {
253
+ compositionPath: `composition.tracks[${i}].id`
254
+ });
240
255
  }
241
256
  if (!["video", "audio", "image", "overlay", "effect"].includes(t.kind)) {
242
- throw new Error(`composition.tracks[${i}].kind: invalid value`);
257
+ throw renderInputError("invalid_composition", `composition.tracks[${i}].kind: invalid value`, {
258
+ compositionPath: `composition.tracks[${i}].kind`,
259
+ ...typeof t.id === "string" ? { trackId: t.id } : {}
260
+ });
243
261
  }
244
262
  if (!Array.isArray(t.contents)) {
245
- throw new Error(`composition.tracks[${i}].contents: expected array`);
263
+ throw renderInputError("invalid_composition", `composition.tracks[${i}].contents: expected array`, {
264
+ compositionPath: `composition.tracks[${i}].contents`,
265
+ trackId: t.id
266
+ });
246
267
  }
247
268
  }
248
269
  if (obj.markers !== void 0 && !Array.isArray(obj.markers)) {
249
- throw new Error("composition.markers: expected array when present");
270
+ throw renderInputError("invalid_composition", "composition.markers: expected array when present", {
271
+ compositionPath: "composition.markers"
272
+ });
250
273
  }
251
274
  if (obj.captions !== void 0) {
252
275
  const c = obj.captions;
253
276
  if (!c || typeof c !== "object") {
254
- throw new Error("composition.captions: expected object when present");
277
+ throw renderInputError("invalid_composition", "composition.captions: expected object when present", {
278
+ compositionPath: "composition.captions"
279
+ });
255
280
  }
256
281
  if (!Array.isArray(c.segments)) {
257
- throw new Error("composition.captions.segments: expected array");
282
+ throw renderInputError("invalid_composition", "composition.captions.segments: expected array", {
283
+ compositionPath: "composition.captions.segments"
284
+ });
258
285
  }
259
286
  if (c.style !== void 0 && (typeof c.style !== "object" || c.style === null)) {
260
- throw new Error("composition.captions.style: expected object when present");
287
+ throw renderInputError("invalid_composition", "composition.captions.style: expected object when present", {
288
+ compositionPath: "composition.captions.style"
289
+ });
261
290
  }
262
291
  if (c.style !== void 0) {
263
292
  const fs = c.style.fontSize;
264
293
  if (fs !== void 0 && (typeof fs !== "number" || fs < 1 || fs > 15)) {
265
- throw new Error(
266
- `composition.captions.style.fontSize: PERCENT of composition height (1-15, default 5) \u2014 got ${String(fs)}. px values are not accepted; a px-intent value renders giant band-overflowing captions. Re-author the style with a percent value.`
294
+ throw renderInputError(
295
+ "invalid_composition",
296
+ `composition.captions.style.fontSize: PERCENT of composition height (1-15, default 5) \u2014 got ${String(fs)}. px values are not accepted; a px-intent value renders giant band-overflowing captions. Re-author the style with a percent value.`,
297
+ { compositionPath: "composition.captions.style.fontSize" }
267
298
  );
268
299
  }
269
300
  }
@@ -299,11 +330,13 @@ function overlayTransitionFields(c, fps) {
299
330
  function rendersNoFrames(c) {
300
331
  return !(c.duration > 0);
301
332
  }
302
- function resolveSrcUrl(mediaId, srcUrls) {
333
+ function resolveSrcUrl(mediaId, srcUrls, locator) {
303
334
  const url = srcUrls[mediaId];
304
335
  if (!url) {
305
- throw new Error(
306
- `Composition references mediaId '${mediaId}' but no presigned URL was supplied. Pre-sign every unique mediaId before calling compositionToRenderInput.`
336
+ throw renderInputError(
337
+ "source_media_not_found",
338
+ `Composition references mediaId '${mediaId}' but no presigned URL was supplied. Pre-sign every unique mediaId before calling compositionToRenderInput.`,
339
+ { ...locator, mediaId }
307
340
  );
308
341
  }
309
342
  return url;
@@ -329,15 +362,24 @@ function projectMediaTrack(track, fps, srcUrls, trajectoryUrls, coViewUrls, traj
329
362
  const c = track.contents[i];
330
363
  if (!("source" in c) || !c.source) continue;
331
364
  if (c.source.kind !== "media") {
332
- throw new Error(
333
- `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on a ${track.kind} track (expected 'media')`
365
+ throw renderInputError(
366
+ "clip_source_track_mismatch",
367
+ `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on a ${track.kind} track (expected 'media')`,
368
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].source` }
334
369
  );
335
370
  }
336
371
  if (rendersNoFrames(c)) continue;
337
- const src = resolveSrcUrl(c.source.mediaId, srcUrls);
338
- if (coViewUrls?.[c.source.mediaId] !== void 0 && c.region !== void 0 && !(c.region.x === 0 && c.region.y === 0 && c.region.w === 1 && c.region.h === 1)) {
339
- throw new Error(
340
- `composition.tracks[${track.id}].contents[${i}] (clip ${c.id}): a co-view clip (captions-behind-subject) cannot also carry a sub-frame region \u2014 the co-view render path does not honor region. Use one or the other.`
372
+ const src = resolveSrcUrl(c.source.mediaId, srcUrls, {
373
+ trackId: track.id,
374
+ clipId: c.id,
375
+ compositionPath: `composition.tracks[${track.id}].contents[${i}].source.mediaId`
376
+ });
377
+ const packedUrl = coViewUrls?.[c.id] ?? coViewUrls?.[c.source.mediaId];
378
+ if (packedUrl !== void 0 && c.region !== void 0 && !(c.region.x === 0 && c.region.y === 0 && c.region.w === 1 && c.region.h === 1)) {
379
+ throw renderInputError(
380
+ "invalid_composition",
381
+ `composition.tracks[${track.id}].contents[${i}] (clip ${c.id}): a co-view clip (captions-behind-subject) cannot also carry a sub-frame region \u2014 the co-view render path does not honor region. Use one or the other.`,
382
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].region` }
341
383
  );
342
384
  }
343
385
  if (track.kind === "audio") {
@@ -412,7 +454,7 @@ function projectMediaTrack(track, fps, srcUrls, trajectoryUrls, coViewUrls, traj
412
454
  } : {},
413
455
  ...trajectoryUrls?.[c.id] !== void 0 ? { cropTrajectoryUrl: trajectoryUrls[c.id] } : {},
414
456
  ...trajectories?.[c.id] !== void 0 ? { cropTrajectory: trajectories[c.id] } : {},
415
- ...coViewUrls?.[c.source.mediaId] !== void 0 ? { packedUrl: coViewUrls[c.source.mediaId] } : {}
457
+ ...packedUrl !== void 0 ? { packedUrl } : {}
416
458
  });
417
459
  }
418
460
  if (firstEmittedSubId !== void 0) {
@@ -444,12 +486,18 @@ function projectImageTrack(track, fps, srcUrls) {
444
486
  const c = track.contents[i];
445
487
  if (!("source" in c) || !c.source) continue;
446
488
  if (c.source.kind !== "media") {
447
- throw new Error(
448
- `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an image track (expected 'media')`
489
+ throw renderInputError(
490
+ "clip_source_track_mismatch",
491
+ `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an image track (expected 'media')`,
492
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].source` }
449
493
  );
450
494
  }
451
495
  if (rendersNoFrames(c)) continue;
452
- const src = resolveSrcUrl(c.source.mediaId, srcUrls);
496
+ const src = resolveSrcUrl(c.source.mediaId, srcUrls, {
497
+ trackId: track.id,
498
+ clipId: c.id,
499
+ compositionPath: `composition.tracks[${track.id}].contents[${i}].source.mediaId`
500
+ });
453
501
  const { startFrame: timelineStartFrames, durationInFrames } = timelineSpanFrames(
454
502
  c.startTime,
455
503
  c.startTime + c.duration,
@@ -501,8 +549,15 @@ function projectOverlayTrack(track, fps, alphaUrls = {}, jsSourceByClipId = {})
501
549
  if (durationInFrames2 === 0) continue;
502
550
  const src = alphaUrls[c.id];
503
551
  if (!src) {
504
- throw new Error(
505
- `composition.tracks[${track.id}].contents[${i}]: alpha-layer clip ${c.id} has no baked alpha (alphaUrls[${c.id}] missing) \u2014 bake before render`
552
+ throw renderInputError(
553
+ "variant_not_baked",
554
+ `composition.tracks[${track.id}].contents[${i}]: alpha-layer clip ${c.id} has no baked alpha (alphaUrls[${c.id}] missing) \u2014 bake before render`,
555
+ {
556
+ trackId: track.id,
557
+ clipId: c.id,
558
+ componentId: c.source.componentId,
559
+ compositionPath: `composition.tracks[${track.id}].contents[${i}].source`
560
+ }
506
561
  );
507
562
  }
508
563
  overlays.push({
@@ -544,8 +599,10 @@ function projectOverlayTrack(track, fps, alphaUrls = {}, jsSourceByClipId = {})
544
599
  continue;
545
600
  }
546
601
  if (c.source.kind !== "overlay") {
547
- throw new Error(
548
- `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an overlay track (expected 'overlay', 'alpha-layer', or 'card')`
602
+ throw renderInputError(
603
+ "clip_source_track_mismatch",
604
+ `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an overlay track (expected 'overlay', 'alpha-layer', or 'card')`,
605
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].source` }
549
606
  );
550
607
  }
551
608
  const { startFrame, durationInFrames } = timelineSpanFrames(
@@ -559,8 +616,10 @@ function projectOverlayTrack(track, fps, alphaUrls = {}, jsSourceByClipId = {})
559
616
  const fresh = jsSourceByClipId[c.id];
560
617
  const sc = typeof fresh === "string" && fresh.length > 0 ? fresh : overlayParams.sourceCode;
561
618
  if (typeof sc !== "string" || sc.length === 0) {
562
- throw new Error(
563
- `composition.tracks[${track.id}].contents[${i}].source: custom overlay has no sourceCode (no fresh jsSource for clip '${c.id}' and no inline params.sourceCode) \u2014 mirror code 'custom_missing_sourcecode'`
619
+ throw renderInputError(
620
+ "custom_missing_sourcecode",
621
+ `composition.tracks[${track.id}].contents[${i}].source: custom overlay has no sourceCode (no fresh jsSource for clip '${c.id}' and no inline params.sourceCode) \u2014 mirror code 'custom_missing_sourcecode'`,
622
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].source` }
564
623
  );
565
624
  }
566
625
  const { componentId: _cid, sourceCode: _sc, ...props } = overlayParams;
@@ -591,8 +650,10 @@ function projectEffectTrack(track, fps) {
591
650
  const c = track.contents[i];
592
651
  if (!("source" in c) || !c.source) continue;
593
652
  if (c.source.kind !== "effect") {
594
- throw new Error(
595
- `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an effect track (expected 'effect')`
653
+ throw renderInputError(
654
+ "clip_source_track_mismatch",
655
+ `composition.tracks[${track.id}].contents[${i}]: kind=${c.source.kind} is invalid on an effect track (expected 'effect')`,
656
+ { trackId: track.id, clipId: c.id, compositionPath: `composition.tracks[${track.id}].contents[${i}].source` }
596
657
  );
597
658
  }
598
659
  const { startFrame, durationInFrames } = timelineSpanFrames(
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ChatErrorView,
3
3
  DirectorTurnContext
4
- } from "./chunk-ZPLJ24OV.js";
4
+ } from "./chunk-D6S3ZKIY.js";
5
5
  import {
6
6
  GenerationArtifact
7
7
  } from "./chunk-73DQTUWY.js";
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  CueframeError,
8
8
  encodeError
9
- } from "./chunk-LLUW26BS.js";
9
+ } from "./chunk-R5BMJ2NX.js";
10
10
 
11
11
  // ../composition/src/projection/cardTokens.ts
12
12
  var CARD_MOTION_VAR_NAMES = [
@@ -154,7 +154,10 @@ function overlapsMs(aStartSec, aDurationSec, bStartSec, bDurationSec) {
154
154
  }
155
155
  function tracksOf(composition) {
156
156
  const tracks = composition?.tracks;
157
- return Array.isArray(tracks) ? tracks : [];
157
+ if (!Array.isArray(tracks)) return [];
158
+ return tracks.filter(
159
+ (track) => track.enabled !== false
160
+ );
158
161
  }
159
162
  function clipsOf(track) {
160
163
  const contents = track.contents;
@@ -210,7 +213,7 @@ async function behindReadinessForTarget(target, mattes) {
210
213
  if (!target) return { state: "no-clip" };
211
214
  const key = await matteIntentKey({ ...target.window, subjectClass: "person" });
212
215
  const entry = mattes?.[key];
213
- if (!entry?.geometryR2Key) return { state: "no-matte", target };
216
+ if (!entry?.geometryUrl && !entry?.geometryR2Key) return { state: "no-matte", target };
214
217
  const presenceFraction = entry.presenceFraction ?? 0;
215
218
  if (presenceFraction < MIN_PRESENCE_FOR_BEHIND) {
216
219
  return { state: "no-subject", target, presenceFraction };
@@ -237,7 +240,9 @@ function matteWindowsByMediaId(composition, behindWindows) {
237
240
  const startSec = typeof trim?.start === "number" ? trim.start : 0;
238
241
  const endSec = typeof trim?.end === "number" ? trim.end : startSec + clip.duration;
239
242
  if (endSec <= startSec) continue;
240
- if (!out.has(mediaId)) out.set(mediaId, { startSec, endSec });
243
+ const windows = out.get(mediaId) ?? [];
244
+ windows.push({ clipId: clip.id, startSec, endSec });
245
+ out.set(mediaId, windows);
241
246
  }
242
247
  }
243
248
  return out;
@@ -1,41 +1,41 @@
1
1
  import {
2
2
  isContrastCritical
3
3
  } from "./chunk-YLDMAZZE.js";
4
- import {
5
- catalog as catalog6
6
- } from "./chunk-BKHGL4MB.js";
7
- import {
8
- catalog as catalog2
9
- } from "./chunk-GMD33ZD7.js";
10
- import {
11
- catalog as catalog8
12
- } from "./chunk-SAMQUUO5.js";
13
- import {
14
- catalog as catalog4
15
- } from "./chunk-RP4SXXLJ.js";
16
4
  import {
17
5
  catalog as catalog7
18
- } from "./chunk-DYZE7JZA.js";
6
+ } from "./chunk-TMIBBD5E.js";
19
7
  import {
20
8
  catalog
21
- } from "./chunk-UQSOS726.js";
9
+ } from "./chunk-6ABIXGLO.js";
22
10
  import {
23
11
  catalog as catalog3
24
12
  } from "./chunk-AWT3P5ZN.js";
13
+ import {
14
+ catalog as catalog6
15
+ } from "./chunk-THJAY7QS.js";
25
16
  import {
26
17
  catalog as catalog5
27
- } from "./chunk-G5BFI32U.js";
18
+ } from "./chunk-XATRRDVG.js";
19
+ import {
20
+ catalog as catalog2
21
+ } from "./chunk-O7GNE4BQ.js";
22
+ import {
23
+ catalog as catalog8
24
+ } from "./chunk-BIBYZJL3.js";
25
+ import {
26
+ catalog as catalog4
27
+ } from "./chunk-3PM6VICZ.js";
28
28
  import {
29
29
  getPrimitiveSubtextParam,
30
30
  getPrimitiveTextParam
31
- } from "./chunk-DCVJWGIA.js";
31
+ } from "./chunk-JY26PIRP.js";
32
32
  import {
33
33
  NEUTRAL_RAMP
34
34
  } from "./chunk-JF4JJAFP.js";
35
35
  import {
36
36
  CueframeError,
37
37
  encodeError
38
- } from "./chunk-LLUW26BS.js";
38
+ } from "./chunk-R5BMJ2NX.js";
39
39
 
40
40
  // ../execution/compose/src/primitiveRegistry.ts
41
41
  var allCatalogs = [
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  waitForJob
3
- } from "./chunk-QETYXKQQ.js";
3
+ } from "./chunk-7V3F5HO4.js";
4
+ import {
5
+ CURATED_TOOLS
6
+ } from "./chunk-PJ4R4N4Q.js";
4
7
  import {
5
8
  GENERATED_OPERATIONS,
6
9
  apiErrorFrom,
@@ -17,10 +20,7 @@ import {
17
20
  sniffImageMediaType,
18
21
  text,
19
22
  withMedia
20
- } from "./chunk-W3SIWT7J.js";
21
- import {
22
- CURATED_TOOLS
23
- } from "./chunk-AO744WIK.js";
23
+ } from "./chunk-RQ2G4DXI.js";
24
24
 
25
25
  // ../mcp/src/prompts.ts
26
26
  var skillListCache = null;
@@ -91,17 +91,17 @@ CLIPPING (find the best short-form moments in a long video): \`suggest_briefs\`
91
91
 
92
92
  Every expensive step has a cheap, inspectable check \u2014 prefer reading a value over rendering and eyeballing:
93
93
  - Framing & timing are data: \`get_media_context\` BEFORE you compose.
94
- - Evidence beats guessing: \`preview_frame\` (whole-composition stills), \`preview_component\` (ONE graphic as a MOTION clip \u2014 the same bake production composites), \`preview_clip\` (a fromSec\u2192toSec window as a watchable MP4, max 60s, capture-priced \u2014 judge a cut or transition at full fidelity WITHOUT paying for a full render). These are STATELESS: nothing to open, warm, or close; concurrent previews do not contend. \`preview_frame\` defaults to the PERSISTED composition and echoes \`previewed.{source, compositionId, etag}\` \u2014 what you saw is what create_render encodes.
94
+ - Evidence beats guessing: \`preview_frame\` (whole-composition stills), \`preview_component\` (ONE authored graphic: \`executionMode:"live"\` returns a PNG image; \`executionMode:"baked"\` returns a transparent VP9 motion clip \u2014 exactly the lane production composites), \`preview_clip\` (a fromSec\u2192toSec window as a watchable MP4, max 60s, capture-priced \u2014 judge a cut or transition at full fidelity WITHOUT paying for a full render). These are STATELESS: nothing to open, warm, or close; concurrent previews do not contend. \`preview_frame\` defaults to the PERSISTED composition and echoes \`previewed.{source, compositionId, etag}\` \u2014 what you saw is what create_render encodes.
95
95
  - Quality is a number: \`score_composition\` returns scores + critique + a checkpointId; the compose result carries the winner's composite. **score vs consult**: score answers "how good IS this" (grounded numbers); \`consult\` answers "what SHOULD I change" (advice + an adoptable fix via \`select_candidate\`).
96
96
 
97
97
  ## Async model
98
98
 
99
99
  Every long job is either polled or pushed \u2014 never guessed:
100
- - \`wait_job\` kinds: \`render\`, \`compose\`, \`suggestions\`, \`verify\` (score jobs), \`preview\` (component clips), \`brand_kit_extract\`, \`consult\`. It blocks up to its window and returns a CONTINUATION when still running \u2014 re-call it.
100
+ - \`wait_job\` kinds: \`media\` (imports/generation), \`render\`, \`compose\`, \`suggestions\`, \`verify\` (score jobs), \`preview_frame\` (composition stills), \`preview\` (component image-or-motion previews), \`brand_kit_extract\`, \`consult\`. It blocks up to its window and returns a CONTINUATION when still running \u2014 re-call it.
101
101
  - Webhooks (\`create_webhook\`): ONE terminal event per kind with status INSIDE the payload \u2014 \`render.completed\`, \`compose.completed\`, \`media.completed\`, \`suggest.completed\` \u2014 plus \`checkpoint.ready\` (a held compose paused for review). Read \`cueframe://webhook-events\` for the full contract before building a receiver.
102
102
  - Presigned URLs (stills, clips, render outputs) expire \u2014 render outputs last ~7 days (refresh via the render's refresh-url op); preview stills/clips ~1 hour. Re-read for a fresh link instead of caching one.
103
103
 
104
- CUSTOM GRAPHICS \u2014 author or FORK: \`create_component\` (tsxSource) from scratch, or \`get_component_source\` on a built-in primitive (e.g. \`cinematic-title\`) to fork its editable module. Iterate author\u2192preview\u2192fix with \`preview_component\` (202 + jobId; \`wait_job(kind:"preview")\` returns the clip URL \u2014 a compile failure lands on the job's FAILED terminal carrying the sanitized compiler error) \u2192 fix via \`update_component\` \u2192 preview again. Place it via \`apply_composition\` as an \`alpha-layer\` clip \u2014 the shared renderer never runs your code (it bakes to transparent video first).
104
+ CUSTOM GRAPHICS \u2014 author or FORK: \`create_component\` (tsxSource) from scratch, or \`get_component_source\` on a built-in primitive (e.g. \`cinematic-title\`) to fork its editable module. Iterate author\u2192preview\u2192fix with \`preview_component\` (202 + jobId; \`wait_job(kind:"preview")\` returns a PNG image for \`executionMode:"live"\` or a VP9 motion URL for \`executionMode:"baked"\`; a compile failure lands on the job's FAILED terminal carrying the sanitized compiler error) \u2192 fix via \`update_component\` \u2192 preview again. Place baked components via \`apply_composition\` as an \`alpha-layer\` clip \u2014 the shared renderer never runs authored source code (it composites the transparent baked video).
105
105
 
106
106
  Cleanup: \`delete_project\` / \`delete_media\` / \`delete_webhook\` / \`delete_composition\`. \`list_projects\` re-orients you in an existing workspace; \`list_media\` (filter by \`source\`/\`tag\`) lists the library.
107
107
 
@@ -436,12 +436,16 @@ function registerCuratedTools(server, ex, opts) {
436
436
  for (const friendly of Object.keys(spec.pathArgs ?? {})) {
437
437
  inputSchema[friendly] = z.string().describe(`${friendly} (path).`);
438
438
  }
439
+ for (const [queryArg, description] of Object.entries(spec.queryArgs ?? {})) {
440
+ inputSchema[queryArg] = z.string().optional().describe(description);
441
+ }
439
442
  const bodySchema = bodySchemaFor(op);
440
443
  if (bodySchema) inputSchema.body = bodySchema;
441
444
  const annotations = { ...op.annotations, ...spec.annotations };
442
445
  server.registerTool(spec.name, { title: spec.title ?? titleCase(spec.name), description: spec.description, inputSchema, annotations }, async (args, extra) => timed(opts?.onEvent, spec.name, async (report) => {
443
446
  const a = args;
444
447
  try {
448
+ const query = Object.keys(spec.queryArgs ?? {}).filter((name) => a[name] !== void 0 && a[name] !== null && a[name] !== "").map((name) => `${encodeURIComponent(name)}=${encodeURIComponent(String(a[name]))}`).join("&");
445
449
  return await dispatchOp(ex, op, (p) => a[reverse[p]], a.body, extra, spec.name, async (res) => {
446
450
  if (spec.okText) return text(spec.okText(a));
447
451
  const json = res.text ? safeParse(res.text) : void 0;
@@ -454,17 +458,17 @@ function registerCuratedTools(server, ex, opts) {
454
458
  if (data.length) return withMedia(payload, data.map((d) => ({ data: d, kind })));
455
459
  }
456
460
  return text(payload);
457
- });
461
+ }, query || void 0);
458
462
  } catch (err) {
459
463
  return errText(`${spec.name} failed: ${fmtErr(err)}`);
460
464
  }
461
465
  }));
462
466
  }
463
467
  registerWaitJob(server, ex, opts?.waitCapMs, opts?.onEvent);
464
- registerPreviewCard(server, ex, opts?.onEvent);
468
+ registerPreviewCard(server, ex, opts?.waitCapMs, opts?.onEvent);
465
469
  }
466
- function registerPreviewCard(server, ex, onEvent) {
467
- const op = opById("previewFrame");
470
+ function registerPreviewCard(server, ex, waitCapMs, onEvent) {
471
+ const op = opById("previewFrameJob");
468
472
  server.registerTool(
469
473
  "preview_card",
470
474
  {
@@ -508,12 +512,19 @@ function registerPreviewCard(server, ex, onEvent) {
508
512
  "preview_card",
509
513
  async (res) => {
510
514
  const json = res.text ? safeParse(res.text) : void 0;
511
- const urls = (Array.isArray(json?.stills) ? json.stills : []).map(
512
- (st) => st?.url
513
- );
515
+ const jobId = json?.jobId;
516
+ if (typeof jobId !== "string" || !jobId) {
517
+ return errText("preview_card enqueue returned no jobId");
518
+ }
519
+ const waitMs = Math.min(waitCapMs ?? 3e4, 3e4);
520
+ const done = await waitForJob(ex, "preview_frame", jobId, void 0, Date.now() + waitMs);
521
+ if (!done.ok) return errText(done.text);
522
+ if (done.stillRunning) return text(`${done.text}
523
+ jobId: ${jobId}`);
524
+ const urls = done.mediaUrls ?? [];
514
525
  const data = await fetchPreviews(urls, 2);
515
526
  report({ preview: { urls: urls.filter(Boolean).length, fetched: data.length } });
516
- const payload = res.text || `previewed card (${a.aspectRatio ?? "9:16"})`;
527
+ const payload = done.text || `previewed card (${a.aspectRatio ?? "9:16"})`;
517
528
  return data.length ? withMedia(payload, data.map((d) => ({ data: d, kind: "image" }))) : text(payload);
518
529
  }
519
530
  );
@@ -529,10 +540,10 @@ function registerWaitJob(server, ex, waitCapMs, onEvent) {
529
540
  {
530
541
  title: "Wait for Job",
531
542
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
532
- description: "Wait for a long-running job and return the resolved result \u2014 a BOUNDED long-poll. Polls the job status (render / compose / consult / clip-suggestions / verify) and blocks up to the transport window (30s on the hosted transport); if the job is still running at the window it returns a `Still running` continuation \u2014 call wait_job again with the same arguments to keep waiting (the job keeps executing server-side; nothing is lost between calls). Call this right after compose / create_render / consult / suggest_briefs / score_composition / preview_component. For event-driven fan-out, create_webhook delivers the terminal instead.",
543
+ description: "Wait for a long-running job and return the resolved result \u2014 a BOUNDED long-poll. Polls job status (media import/generation / render / compose / consult / clip-suggestions / verify / preview-frame) and blocks up to the transport window (30s on the hosted transport); if still running, it returns a continuation \u2014 call wait_job again with the same arguments (the job keeps executing server-side). Call this after import_media / generate_media / finalize_upload / import_resource / compose / create_render / consult / suggest_briefs / score_composition / preview_frame / preview_component. For event-driven fan-out, create_webhook delivers the terminal instead.",
533
544
  inputSchema: {
534
- kind: z.enum(["render", "suggestions", "compose", "verify", "preview", "brand_kit_extract", "consult"]).describe("What to wait on: a render job, a compose job, a consult advisory, AI clip-suggestion analysis, or a generic async job (verify / preview / brand-kit extract \u2014 the kind is named in the enqueue receipt)."),
535
- id: z.string().describe('kind="render": renderId. kind="compose": composeJobId. kind="consult": the consultJobId from the consult receipt (surfaces the advisory envelope \u2014 assessment, proposals, principles). kind="suggestions": mediaItemId. kind="verify"/"preview"/"brand_kit_extract": the jobId from the enqueue receipt.'),
545
+ kind: z.enum(["media", "render", "suggestions", "compose", "verify", "preview_frame", "preview", "brand_kit_extract", "consult"]).describe("What to wait on: media ingest/generation, render, compose, consult, clip-suggestion analysis, or a generic async job (verify / preview_frame / preview / brand-kit extract \u2014 use the enqueue receipt kind)."),
546
+ id: z.string().describe('kind="media": mediaItemId returned by import/generate/finalize/import_resource. kind="render": renderId. kind="compose": composeJobId. kind="consult": consultJobId. kind="suggestions": mediaItemId. Generic kinds use the jobId from the enqueue receipt.'),
536
547
  projectId: z.string().optional().describe('Required when kind="render", "compose", or "consult".'),
537
548
  timeoutMs: z.number().int().min(1e3).max(30 * 60 * 1e3).optional().describe("Maximum wait in ms (default 30 min for render/compose, 5 min for suggestions).")
538
549
  }
@@ -542,7 +553,7 @@ function registerWaitJob(server, ex, waitCapMs, onEvent) {
542
553
  if ((kind === "render" || kind === "compose" || kind === "consult") && !args.projectId) {
543
554
  return errText(`wait_job(kind="${kind}") requires a projectId.`);
544
555
  }
545
- const defaultCap = kind === "suggestions" ? 5 * 60 * 1e3 : 30 * 60 * 1e3;
556
+ const defaultCap = kind === "suggestions" || kind === "media" ? 5 * 60 * 1e3 : 30 * 60 * 1e3;
546
557
  const requested = args.timeoutMs ?? defaultCap;
547
558
  const deadline = Date.now() + (waitCapMs ? Math.min(requested, waitCapMs) : requested);
548
559
  const res = await waitForJob(ex, kind, args.id, args.projectId, deadline);
@@ -2,7 +2,7 @@ import {
2
2
  COMPOSE_PLANNER_TOOLS,
3
3
  COMPOSE_ROLE_TOOLS,
4
4
  dispatchComposeRoleTool
5
- } from "./chunk-BZZTVOGG.js";
5
+ } from "./chunk-D2EGO543.js";
6
6
 
7
7
  // ../authoring/src/agent/buildTools.ts
8
8
  import { tool } from "ai";
@@ -135,6 +135,22 @@ var buildPlannerTools = (p) => {
135
135
 
136
136
  // ../authoring/src/agent/errors.ts
137
137
  import { APICallError, TypeValidationError } from "ai";
138
+ var BODY_EXCERPT = 200;
139
+ function providerMessage(responseBody) {
140
+ if (!responseBody) return void 0;
141
+ try {
142
+ const body = JSON.parse(responseBody);
143
+ const msg = body?.error?.message ?? body?.message;
144
+ return msg == null ? void 0 : String(msg);
145
+ } catch {
146
+ return void 0;
147
+ }
148
+ }
149
+ function bodyExcerpt(responseBody) {
150
+ const trimmed = responseBody?.trim();
151
+ if (!trimmed) return void 0;
152
+ return trimmed.replace(/\s+/g, " ").slice(0, BODY_EXCERPT);
153
+ }
138
154
  function extractProviderError(err) {
139
155
  if (APICallError.isInstance(err)) {
140
156
  const status = err.statusCode;
@@ -144,17 +160,16 @@ function extractProviderError(err) {
144
160
  if (status === 429) {
145
161
  return "API rate limit or quota exceeded. Try again later.";
146
162
  }
163
+ const detail = providerMessage(err.responseBody);
147
164
  if (status === 413 || status === 400) {
148
- if (err.responseBody) {
149
- try {
150
- const body = JSON.parse(err.responseBody);
151
- const msg = body?.error?.message ?? body?.message;
152
- if (msg) return String(msg).slice(0, 200);
153
- } catch {
154
- }
155
- }
165
+ if (detail) return detail.slice(0, 200);
156
166
  }
157
- return err.message.slice(0, 300);
167
+ const where = status === void 0 ? "" : ` (HTTP ${status})`;
168
+ const evidence = detail ?? bodyExcerpt(err.responseBody);
169
+ return (evidence ? `${err.message}${where}: ${evidence}` : `${err.message}${where}`).slice(
170
+ 0,
171
+ 300
172
+ );
158
173
  }
159
174
  if (TypeValidationError.isInstance(err)) {
160
175
  return "Invalid response from AI provider. The provider may be misconfigured or unavailable.";