@cueframe/kernel 0.2.22 → 0.2.23
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/dist/_members/mcp/core.d.ts +16 -1
- package/dist/{chunk-DJWCD3RF.js → chunk-3OOMVQ6I.js} +4 -4
- package/dist/{chunk-NG7DP46H.js → chunk-EDR75OU7.js} +1 -1
- package/dist/{chunk-BAVEHXVC.js → chunk-LPFVUT3S.js} +7 -6
- package/dist/{chunk-URQQTAHZ.js → chunk-RGKDDR7H.js} +8 -2
- package/dist/compose.js +7 -7
- package/dist/composition-ops.js +84 -28
- package/dist/mcp/adapter.js +3 -3
- package/dist/mcp/core.js +3 -1
- package/dist/mcp/curation.js +1 -1
- package/dist/mcp/server.js +4 -4
- package/dist/mcp.js +4 -4
- package/dist/primitives/effects.js +2 -2
- package/dist/primitives/ui-blocks.js +2 -2
- package/dist/primitives.js +7 -7
- package/package.json +11 -11
- package/dist/{chunk-VLJOIUHL.js → chunk-A76GTLSA.js} +3 -3
- package/dist/{chunk-LD4XQQRL.js → chunk-AMKPFIF4.js} +3 -3
|
@@ -38,6 +38,19 @@ export type ToolResult = {
|
|
|
38
38
|
structuredContent?: Record<string, unknown>;
|
|
39
39
|
};
|
|
40
40
|
export declare function text(s: string): ToolResult;
|
|
41
|
+
/**
|
|
42
|
+
* A JSON response, carried BOTH ways: the rendered prose a human reads, and the
|
|
43
|
+
* parsed object a program can consume.
|
|
44
|
+
*
|
|
45
|
+
* Curated tools used to return prose only, so `create_render` promised
|
|
46
|
+
* `{id,status,warnings?}` and delivered "Render queued.\n\nrenderId: …". A
|
|
47
|
+
* generic MCP consumer had to scrape it (CUE-15 P0). `structuredContent` is the
|
|
48
|
+
* protocol's channel for exactly this; the text block stays as display.
|
|
49
|
+
*
|
|
50
|
+
* Attached only for a non-null, non-array OBJECT, which is what the protocol
|
|
51
|
+
* allows — a bare array or scalar would be rejected by a validating client.
|
|
52
|
+
*/
|
|
53
|
+
export declare function textWithData(s: string, data: unknown): ToolResult;
|
|
41
54
|
export declare function errText(s: string): ToolResult;
|
|
42
55
|
export declare function firstText(r: ToolResult): string;
|
|
43
56
|
export declare function sniffImageMediaType(base64: string): string | undefined;
|
|
@@ -45,7 +58,9 @@ export declare function sniffAudioMediaType(base64: string): string | undefined;
|
|
|
45
58
|
export declare function withMedia(payload: string, media: {
|
|
46
59
|
data: string;
|
|
47
60
|
kind: 'image' | 'audio';
|
|
48
|
-
}[]
|
|
61
|
+
}[],
|
|
62
|
+
/** The parsed response, carried alongside the media for programmatic callers. */
|
|
63
|
+
data?: unknown): ToolResult;
|
|
49
64
|
export declare function fetchAsBase64(url: string, opts?: {
|
|
50
65
|
timeoutMs?: number;
|
|
51
66
|
maxBytes?: number;
|
|
@@ -312,7 +312,7 @@ Call wait_job(kind="compose", id="${j.composeJobId}", projectId="${a.projectId}"
|
|
|
312
312
|
name: "apply_composition",
|
|
313
313
|
operationId: "applyComposition",
|
|
314
314
|
pathArgs: { projectId: "id" },
|
|
315
|
-
description: 'Atomically apply an array of CompositionOps to a project composition. All ops succeed or none do (transactional). Pass `if_match` for optimistic-concurrency control (409 stale_etag on mismatch) and `dry_run: true` to validate the batch without persisting. Use this to seed a composition (add media clips) or make targeted edits (set a crop intent, reorder clips, set the format). CAPTIONS: attach content with {type:"captions.fromTranscript", mediaId, window?} \u2014 the server slices the cached word-timed transcript, rebases times, and sentence-splits into segments (no pasting words; 422 media_no_transcript if the media has no speech); style it with {type:"setCaptionStyle", style}; or set explicit words with {type:"setCaptions", segments, style?} (e.g. translations or your own VO timings). Brand is NOT set here \u2014 it lives on the project (create_project / PATCH /projects/:id
|
|
315
|
+
description: 'Atomically apply an array of CompositionOps to a project composition. All ops succeed or none do (transactional). Pass `if_match` for optimistic-concurrency control (409 stale_etag on mismatch) and `dry_run: true` to validate the batch without persisting. Use this to seed a composition (add media clips) or make targeted edits (set a crop intent, reorder clips, set the format). CAPTIONS: attach content with {type:"captions.fromTranscript", mediaId, window?} \u2014 the server slices the cached word-timed transcript, rebases times, and sentence-splits into segments (no pasting words; 422 media_no_transcript if the media has no speech); style it with {type:"setCaptionStyle", style}; or set explicit words with {type:"setCaptions", segments, style?} (e.g. translations or your own VO timings). Brand is NOT set here \u2014 it lives on the project (create_project / update_project with brandKitId \u2014 or PATCH /projects/:id over REST). CARDS: a {kind:"card", html, tokens} clip projects each `tokens` KEY `x` to the CSS custom property `--cf-x`, so the html must read it as `var(--cf-x)` \u2014 write `tokens:{"plate":"#0af"}` + `background:var(--cf-plate)`. Do NOT put dashes in the key: `"--plate"` becomes `--cf---plate` and your `var(--plate)` then resolves to NOTHING, which CSS silently degrades to a transparent background and black text. Responses carry `warnings[]` when a card reads a var nothing defines. SCENE SHOTS: for a 3D product shot \u2014 a tilted page screenshot, a lit laptop/phone showing a real screenshot, two-colour type, a colour-field backdrop, focus/grain/vignette and a camera move \u2014 use {type:"scene.add", clipId, newTrack|trackId, startTime, duration, scene, assets} and revise it with {type:"scene.update", clipId, scene?, assets?, startTime?, duration?}. You author a scene SPEC, never wrapper TSX; the server registers the component for you. There is NO built-in scene primitive in list_catalog \u2014 READ cueframe://scene-shot first for the JSON schema, the canonical V2 world-objects recipe with nested groups, slabs, pages, phones, laptops, world/screen text, admitted surfaces, camera motion, lighting, and the current resource limits.',
|
|
316
316
|
okFormat: (j, a) => {
|
|
317
317
|
const warns = formatWarnings(j);
|
|
318
318
|
if (j && typeof j.valid === "boolean") {
|
|
@@ -348,7 +348,7 @@ ${JSON.stringify(r.errors ?? [], null, 2)}${warns}`;
|
|
|
348
348
|
name: "create_render",
|
|
349
349
|
operationId: "createRender",
|
|
350
350
|
pathArgs: { projectId: "id" },
|
|
351
|
-
description: "Queue an MP4 render of a project's composition. Returns { id (renderId), status, warnings? } \u2014 `warnings[]` carries non-fatal advisories (omitted when none). The render themes from the project's brand kit (bind one via create_project / PATCH /projects/:id
|
|
351
|
+
description: "Queue an MP4 render of a project's composition. Returns { id (renderId), status, warnings? } \u2014 `warnings[]` carries non-fatal advisories (omitted when none). The render themes from the project's brand kit (bind one via create_project / update_project with brandKitId \u2014 or PATCH /projects/:id over REST; without one the output is unbranded). Then call wait_job(kind=\"render\", id=renderId, projectId=...) to block until the file is ready and get the download URL, or register a webhook (create_webhook on render.completed \u2014 status rides the payload).",
|
|
352
352
|
okFormat: (j, a) => `Render queued.
|
|
353
353
|
|
|
354
354
|
renderId: ${j.id}
|
|
@@ -552,7 +552,7 @@ Poll get_media_facts(mediaItemId="${a.mediaItemId}", kind="${a.body?.kind}", sta
|
|
|
552
552
|
{
|
|
553
553
|
name: "create_project",
|
|
554
554
|
operationId: "createProject",
|
|
555
|
-
description: "Create a new project \u2014 the unit you compose and render into. compose / apply_composition / create_render / the preview family all require a projectId; this mints one. Pass name (required) plus optionally a format (aspectRatio/fps/resolution) and brandKitId. brandKitId binds a brand kit to the PROJECT (pass the kitId from create_brand_kit): colors/fonts/motion theme every render of this project automatically (omit it and the output is unbranded). Bind or change it later via PATCH /projects/:id. Returns the ProjectResponse (id + metadata)."
|
|
555
|
+
description: "Create a new project \u2014 the unit you compose and render into. compose / apply_composition / create_render / the preview family all require a projectId; this mints one. Pass name (required) plus optionally a format (aspectRatio/fps/resolution) and brandKitId. brandKitId binds a brand kit to the PROJECT (pass the kitId from create_brand_kit): colors/fonts/motion theme every render of this project automatically (omit it and the output is unbranded). Bind or change it later via update_project (PATCH /projects/:id over REST). Returns the ProjectResponse (id + metadata)."
|
|
556
556
|
},
|
|
557
557
|
{
|
|
558
558
|
name: "new_composition",
|
|
@@ -806,7 +806,7 @@ Render it with create_render(projectId="${a.projectId}", body={ compositionId: "
|
|
|
806
806
|
{
|
|
807
807
|
name: "create_brand_kit",
|
|
808
808
|
operationId: "createBrandKit",
|
|
809
|
-
description: "Create or UPSERT a brand kit (re-POSTing the same kitId updates it in place \u2014 this is also the brand-kit UPDATE path). Sets fonts/colors/logo. This is brand step 0 of the workflow: author the kit, then bind it to a PROJECT so colors/fonts/motion theme the output AUTOMATICALLY \u2014 pass its kitId as brandKitId to create_project, or attach it to an existing project via PATCH /projects/:id. Without a bound kit, create_render produces UNBRANDED output. Tenant-scoped (no project arg)."
|
|
809
|
+
description: "Create or UPSERT a brand kit (re-POSTing the same kitId updates it in place \u2014 this is also the brand-kit UPDATE path). Sets fonts/colors/logo. This is brand step 0 of the workflow: author the kit, then bind it to a PROJECT so colors/fonts/motion theme the output AUTOMATICALLY \u2014 pass its kitId as brandKitId to create_project, or attach it to an existing project via update_project (PATCH /projects/:id over REST). Without a bound kit, create_render produces UNBRANDED output. Tenant-scoped (no project arg)."
|
|
810
810
|
},
|
|
811
811
|
{
|
|
812
812
|
name: "extract_brand_kit",
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
querySchemaShape,
|
|
3
3
|
serializeQuery,
|
|
4
4
|
waitForJob
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EDR75OU7.js";
|
|
6
6
|
import {
|
|
7
7
|
CURATED_TOOLS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3OOMVQ6I.js";
|
|
9
9
|
import {
|
|
10
10
|
GENERATED_OPERATIONS,
|
|
11
11
|
apiErrorFrom,
|
|
@@ -21,8 +21,9 @@ import {
|
|
|
21
21
|
safeParse,
|
|
22
22
|
sniffImageMediaType,
|
|
23
23
|
text,
|
|
24
|
+
textWithData,
|
|
24
25
|
withMedia
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-RGKDDR7H.js";
|
|
26
27
|
|
|
27
28
|
// ../mcp/src/prompts.ts
|
|
28
29
|
var skillListCache = null;
|
|
@@ -3616,7 +3617,7 @@ function registerResources(server, ex) {
|
|
|
3616
3617
|
}),
|
|
3617
3618
|
{
|
|
3618
3619
|
title: "Component catalog",
|
|
3619
|
-
description: "The component catalog: the FULL built-in primitive catalog (
|
|
3620
|
+
description: "The component catalog: the FULL built-in primitive catalog (lower-third, cinematic-title, color-grade, the `scenes`-category templates \u2026) PLUS your org-installed custom components. This is 'discover what to build with'. resources/list enumerates EVERY entry with its discovery facets (source/category/kind/tier/useCase) and a placement hint; read one for its full prop schema. NOT only your authored components. NOTE the word 'scene' means two different things: the `scenes` CATEGORY here is composed built-in templates you place by primitiveId, whereas a SCENE SHOT (the scene.add op, cueframe://scene-shot) is a 3D spec you author and has no catalog entry at all. URI: cueframe://component/{componentId}.",
|
|
3620
3621
|
mimeType: "application/json"
|
|
3621
3622
|
},
|
|
3622
3623
|
async (uri, { componentId }) => jsonResource(uri, await read(ex, "getComponent", () => String(componentId)))
|
|
@@ -3760,9 +3761,9 @@ function registerCuratedTools(server, ex, opts) {
|
|
|
3760
3761
|
const urls = spec.preview.urls(json).filter(Boolean);
|
|
3761
3762
|
const data = await fetchPreviews(urls, spec.preview.cap ?? 12);
|
|
3762
3763
|
report({ preview: { urls: urls.length, fetched: data.length } });
|
|
3763
|
-
if (data.length) return withMedia(payload, data.map((d) => ({ data: d, kind })));
|
|
3764
|
+
if (data.length) return withMedia(payload, data.map((d) => ({ data: d, kind })), json);
|
|
3764
3765
|
}
|
|
3765
|
-
return
|
|
3766
|
+
return textWithData(payload, json);
|
|
3766
3767
|
}, query);
|
|
3767
3768
|
} catch (err) {
|
|
3768
3769
|
return errText(`${spec.name} failed: ${fmtErr(err)}`);
|
|
@@ -9344,6 +9344,10 @@ function encodePaymentSignature(payload) {
|
|
|
9344
9344
|
function text(s) {
|
|
9345
9345
|
return { content: [{ type: "text", text: s }] };
|
|
9346
9346
|
}
|
|
9347
|
+
function textWithData(s, data) {
|
|
9348
|
+
const structured = data !== null && typeof data === "object" && !Array.isArray(data) ? data : void 0;
|
|
9349
|
+
return structured ? { content: [{ type: "text", text: s }], structuredContent: structured } : { content: [{ type: "text", text: s }] };
|
|
9350
|
+
}
|
|
9347
9351
|
function errText(s) {
|
|
9348
9352
|
return { content: [{ type: "text", text: s }], isError: true };
|
|
9349
9353
|
}
|
|
@@ -9400,7 +9404,7 @@ function sniffAudioMediaType(base64) {
|
|
|
9400
9404
|
if (head.length >= 4 && head[0] === 255 && (head[1] & 224) === 224 && (head[1] >> 3 & 3) !== 1 && (head[1] >> 1 & 3) !== 0 && head[2] >> 4 > 0 && head[2] >> 4 < 15 && (head[2] >> 2 & 3) !== 3) return "audio/mpeg";
|
|
9401
9405
|
return void 0;
|
|
9402
9406
|
}
|
|
9403
|
-
function withMedia(payload, media) {
|
|
9407
|
+
function withMedia(payload, media, data) {
|
|
9404
9408
|
const blocks = [{ type: "text", text: payload }];
|
|
9405
9409
|
for (const m of media) {
|
|
9406
9410
|
if (!m.data) continue;
|
|
@@ -9411,7 +9415,8 @@ function withMedia(payload, media) {
|
|
|
9411
9415
|
}
|
|
9412
9416
|
blocks.push({ type: m.kind, data: m.data, mimeType });
|
|
9413
9417
|
}
|
|
9414
|
-
|
|
9418
|
+
const structured = data !== null && typeof data === "object" && !Array.isArray(data) ? data : void 0;
|
|
9419
|
+
return structured ? { content: blocks, structuredContent: structured } : { content: blocks };
|
|
9415
9420
|
}
|
|
9416
9421
|
var MAX_PREVIEW_BYTES = 2 * 1024 * 1024;
|
|
9417
9422
|
var MAX_PREVIEW_BYTES_TOTAL = 3 * 1024 * 1024;
|
|
@@ -9590,6 +9595,7 @@ async function dispatchOp(ex, op, mapArg, body, extra, label, formatOk, query) {
|
|
|
9590
9595
|
export {
|
|
9591
9596
|
GENERATED_OPERATIONS,
|
|
9592
9597
|
text,
|
|
9598
|
+
textWithData,
|
|
9593
9599
|
errText,
|
|
9594
9600
|
firstText,
|
|
9595
9601
|
sniffImageMediaType,
|
package/dist/compose.js
CHANGED
|
@@ -5,9 +5,6 @@ import {
|
|
|
5
5
|
import "./chunk-JQMPHKLU.js";
|
|
6
6
|
import "./chunk-ZZRBKGDA.js";
|
|
7
7
|
import "./chunk-GULDS3VE.js";
|
|
8
|
-
import {
|
|
9
|
-
catalog as catalog4
|
|
10
|
-
} from "./chunk-YV5AYMNK.js";
|
|
11
8
|
import {
|
|
12
9
|
catalog as catalog7
|
|
13
10
|
} from "./chunk-PRSRV7AT.js";
|
|
@@ -22,23 +19,26 @@ import {
|
|
|
22
19
|
import "./chunk-QGAWDLYX.js";
|
|
23
20
|
import {
|
|
24
21
|
catalog as catalog6
|
|
25
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-A76GTLSA.js";
|
|
26
23
|
import "./chunk-S5H6GH6M.js";
|
|
27
|
-
import "./chunk-QAGGJHAF.js";
|
|
28
24
|
import {
|
|
29
25
|
catalog as catalog5
|
|
30
26
|
} from "./chunk-RAXHCRVV.js";
|
|
31
27
|
import {
|
|
32
28
|
catalog as catalog2
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
import "./chunk-MFHXCHRI.js";
|
|
29
|
+
} from "./chunk-AMKPFIF4.js";
|
|
35
30
|
import {
|
|
36
31
|
catalog as catalog8
|
|
37
32
|
} from "./chunk-RL5SO653.js";
|
|
38
33
|
import "./chunk-LT4PWSR2.js";
|
|
39
34
|
import "./chunk-FWSJLHSV.js";
|
|
40
35
|
import "./chunk-ZFEXATWN.js";
|
|
36
|
+
import {
|
|
37
|
+
catalog as catalog4
|
|
38
|
+
} from "./chunk-YV5AYMNK.js";
|
|
41
39
|
import "./chunk-XHGZ2E77.js";
|
|
40
|
+
import "./chunk-QAGGJHAF.js";
|
|
41
|
+
import "./chunk-MFHXCHRI.js";
|
|
42
42
|
import "./chunk-W2245F6G.js";
|
|
43
43
|
import "./chunk-DEDZKZ6G.js";
|
|
44
44
|
import "./chunk-TZ7DKL2G.js";
|
package/dist/composition-ops.js
CHANGED
|
@@ -490,20 +490,48 @@ function resolveClipKind(clip, track) {
|
|
|
490
490
|
return resolved;
|
|
491
491
|
}
|
|
492
492
|
var CompositionOp = z.discriminatedUnion("type", [
|
|
493
|
-
z.object({ type: z.literal("clip.add"), clip: TimelineClip, trackId: z.string().optional(), newTrack: z.boolean().optional(), newTrackId: z.string().optional() }).strict()
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
z.object({ type: z.literal("
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
z.object({ type: z.literal("
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
z.object({ type: z.literal("
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
z.object({ type: z.literal("
|
|
506
|
-
|
|
493
|
+
z.object({ type: z.literal("clip.add"), clip: TimelineClip, trackId: z.string().optional(), newTrack: z.boolean().optional(), newTrackId: z.string().optional() }).strict().describe(
|
|
494
|
+
"Add a clip to the timeline. The clip self-routes to a track by FAMILY (`clip.kind`, else derived from `source.kind`, else the target track) \u2014 a `media` clip MUST carry `kind` (video|audio|image) or a `trackId`, else it is rejected as ambiguous. `trackId` targets an existing SAME-family track; `newTrack:true` (with optional pinned `newTrackId`) creates a fresh track of that family."
|
|
495
|
+
),
|
|
496
|
+
z.object({ type: z.literal("clip.remove"), clipId: z.string() }).strict().describe(
|
|
497
|
+
"Remove a clip by id (located across every track)."
|
|
498
|
+
),
|
|
499
|
+
z.object({ type: z.literal("clip.update"), clipId: z.string(), patch: TimelineClip.partial() }).strict().describe(
|
|
500
|
+
"Patch an existing clip by id (cross-family). The patch is a partial TimelineClip. NOTE: `source` is REPLACED wholesale \u2014 the patch merges at the top level only, so a partial `source` WIPES the source fields you omit. Patch the whole source object when changing it. (To change reframe/excluded ranges, prefer setCropIntents / addExcludedRange, not a source patch.)"
|
|
501
|
+
),
|
|
502
|
+
z.object({ type: z.literal("removeClipsByMediaId"), mediaId: z.string() }).strict().describe(
|
|
503
|
+
"Remove EVERY clip sourced from a given mediaId (e.g. after deleting that media)."
|
|
504
|
+
),
|
|
505
|
+
z.object({ type: z.literal("loadOverlays"), clips: z.array(TimelineClip) }).strict().describe(
|
|
506
|
+
"Replace the overlay channel wholesale with the given clips (bulk set, not a merge)."
|
|
507
|
+
),
|
|
508
|
+
z.object({ type: z.literal("addMarker"), marker: Marker }).strict().describe(
|
|
509
|
+
"Add a timeline marker (a named time point/range; carry extensions in `metadata`)."
|
|
510
|
+
),
|
|
511
|
+
z.object({ type: z.literal("removeMarker"), markerId: z.string() }).strict().describe(
|
|
512
|
+
"Remove a marker by id."
|
|
513
|
+
),
|
|
514
|
+
z.object({ type: z.literal("updateMarker"), markerId: z.string(), updates: Marker.partial() }).strict().describe(
|
|
515
|
+
"Patch a marker's fields by id (partial merge)."
|
|
516
|
+
),
|
|
517
|
+
z.object({ type: z.literal("setCropIntents"), clipId: z.string(), segments: z.array(ReframeSegment).nullable() }).strict().describe(
|
|
518
|
+
"Set (or CLEAR, with `segments: null`) the camera/reframe channel on a MEDIA clip \u2014 the time-aligned source\u2192output viewport (focus, zoom, ease, bias). This is the PREFERRED way to author reframing; do NOT reframe via a whole-source `clip.update` patch. Segments tile the clip's duration."
|
|
519
|
+
),
|
|
520
|
+
z.object({ type: z.literal("setEffects"), clipId: z.string(), effects: z.array(PerClipEffect) }).strict().describe(
|
|
521
|
+
"Set (or CLEAR, with `effects: []`) a clip's EFFECT channel \u2014 the registered effect primitives stacked onto that clip, each `{ primitiveId, params? }`. WHOLESALE: the array REPLACES the clip's current effects, so send the full stack (read the clip first to add one). This is the ONLY way to change effects on an existing clip \u2014 do NOT reach for a `clip.update` patch, whose top-level merge is the source-clobbering footgun documented above."
|
|
522
|
+
),
|
|
523
|
+
z.object({ type: z.literal("setCaptionStyle"), style: CaptionStyle.partial() }).strict().describe(
|
|
524
|
+
"Merge style overrides (font/color/position/emphasis) onto the composition's caption layer. Partial \u2014 omitted fields keep their current value; creates the caption container if absent."
|
|
525
|
+
),
|
|
526
|
+
z.object({ type: z.literal("setCaptionDepth"), zPlane: z.enum(["front", "behind-subject"]) }).strict().describe(
|
|
527
|
+
"Set the caption compositing plane. Use `behind-subject` to place captions behind the segmented foreground subject; use `front` for conventional captions above all video layers."
|
|
528
|
+
),
|
|
529
|
+
z.object({ type: z.literal("setCaptions"), segments: z.array(CaptionSegment), style: CaptionStyle.partial().optional() }).strict().describe(
|
|
530
|
+
"Replace the caption SEGMENTS wholesale \u2014 author the word-timed caption layer directly (each segment = one sentence/page of `words` with timeline-ms `startMs`/`endMs`, optional `emphasis`). This is how a client with its OWN word timings (e.g. a generated VO take) gets word-synced captions without a source transcript; the compose lane's transcript slice writes the same layer. `style`, when given, merges with setCaptionStyle semantics; an omitted style keeps the existing one. Renderer paginates within a segment and never pools words across two \u2014 keep segments sentence-bounded."
|
|
531
|
+
),
|
|
532
|
+
z.object({ type: z.literal("applyMotionPreset"), clipId: z.string(), preset: z.string(), params: z.object({ enterMs: z.number().optional(), exitMs: z.number().optional(), staggerMs: z.number().optional() }).strict().optional() }).strict().describe(
|
|
533
|
+
"Shell a STATIC `card` clip with a frame-driven MOTION preset \u2014 the public card-shelling op (the layout renders VERBATIM; only the container animates in/out). The server wraps the card in the chosen `preset` (fade-up / slide-in-left / slide-in-right / scale-pop / stagger-reveal), transpiles it, mints it as a LIVE component, and swaps the clip source to that component (the bakeless live lane \u2014 no box). `params` tunes timing (`enterMs`/`exitMs`, `staggerMs` for stagger-reveal). The target must be a static card (components already carry motion; library overlays already move); re-run overwrites idempotently ONLY while the target is still a card (an uncompilable shell); once shelled, the clip is a COMPONENT \u2014 to change its motion, remove and re-add the card, then re-shell. Honored under `dry_run` (validates preset + target without transpiling or persisting). ORDERING: the preset resolves its target against the PERSISTED composition \u2014 a card added in the SAME batch is not yet visible to it. Persist the clip.add batch first, then shell in a following call."
|
|
534
|
+
),
|
|
507
535
|
// Scene shots (spec §"Authoring, persistence, and discovery"). Route-materialized: the host
|
|
508
536
|
// registers the generated wrapper source through its component store and rewrites these to
|
|
509
537
|
// addTrack / clip.add / clip.update carrying `props.componentRef`; the agent edits a scene
|
|
@@ -535,24 +563,52 @@ var CompositionOp = z.discriminatedUnion("type", [
|
|
|
535
563
|
scene: SceneShotSpecV2.optional(),
|
|
536
564
|
assets: SceneAssetBindings.optional()
|
|
537
565
|
}).strict().describe("Revise a scene shot in place by clip id. Send a replacement `scene` and/or `assets`; timing changes use the ordinary clip timing fields (`startTime`, `duration`, `transitionIn`). Omitted fields keep their persisted values and the MERGED result is re-validated as a whole, so a partial edit cannot leave the shot invalid. Changing only values or asset IDs updates props and bindings and REUSES the pinned source; changing the referenced SLOT SET regenerates the wrapper manifest and registers a new immutable source version atomically. Undo restores the source reference, spec, bindings and timing together. Topology, asset bindings, text content, font properties, device kind and colours are STATIC within a shot's animation \u2014 change them here (a revised spec) rather than trying to animate them. This is not a source trim or slip: a shortened or extended clip resamples the SAME normalized animation over its new duration, and trim/slip requests on generated animation are rejected rather than reinterpreted as media trims. In one batch, `scene.update` may target a shot added by an earlier `scene.add`."),
|
|
538
|
-
z.object({ type: z.literal("materializeGrid"), clipId: z.string(), grid: z.enum(["beat", "word", "shot"]), maxMarkers: z.number().int().positive().max(2e3).optional() }).strict()
|
|
566
|
+
z.object({ type: z.literal("materializeGrid"), clipId: z.string(), grid: z.enum(["beat", "word", "shot"]), maxMarkers: z.number().int().positive().max(2e3).optional() }).strict().describe(
|
|
567
|
+
'Materialize a clip\'s SOURCE-media temporal GRID as timeline markers \u2014 the rhythm authority you cut to. `grid:"beat"` reads a MUSIC bed\'s beat map (get_media_context.beatGrid), `grid:"word"` the VO word onsets (wordGrid); each grid point is projected from media time to TIMELINE time through the clip\'s placement (startTime, trim, playbackRate, excludedRanges) and written as a `kind:"beat"|"word"` marker (`metadata.sourceClipId` set). Points outside the clip\'s visible window are skipped. Re-running REPLACES the prior markers from the same clip+grid (idempotent). Land cuts and transition MIDPOINTS on the markers (a 0.5s transition starts 0.25s before its marker). `maxMarkers` (default 500, ceiling 2000) \u2014 exceeding it fails loud with the count. `grid:"shot"` is not yet exposed (shot_grid_unavailable). The target must be a media clip; absent evidence fails loud (grid_unavailable) naming how to get it (declare audioRole:"music" at ingest / transcribe).'
|
|
568
|
+
),
|
|
539
569
|
z.object({
|
|
540
570
|
type: z.literal("captions.fromTranscript"),
|
|
541
571
|
mediaId: z.string().min(1),
|
|
542
572
|
window: z.object({ startSec: z.number().min(0), endSec: z.number().positive() }).strict().optional()
|
|
543
|
-
}).strict()
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
z.object({ type: z.literal("
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
z.object({ type: z.literal("
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
z.object({ type: z.literal("
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
573
|
+
}).strict().describe(
|
|
574
|
+
"Attach caption CONTENT from the media's cached transcript \u2014 no pasting words. ROUTE-MATERIALIZED like applyMotionPreset/materializeGrid: the server slices the word-timed transcript to `window` (source seconds; absent = the whole media), rebases times, sentence-splits into segments, and applies it as `setCaptions`. 422 media_no_transcript when the media has no transcript or no words in the window. For your OWN word timings use setCaptions directly."
|
|
575
|
+
),
|
|
576
|
+
z.object({ type: z.literal("setFormat"), format: Format.pick({ aspectRatio: true, fps: true, resolution: true }) }).strict().describe(
|
|
577
|
+
"Set the output format \u2014 `aspectRatio` (16:9|9:16|1:1|4:5) plus optional `fps` and `resolution`. Merges: an omitted field keeps the current value."
|
|
578
|
+
),
|
|
579
|
+
z.object({ type: z.literal("addTrack"), kind: Track.shape.kind, name: z.string().optional(), id: z.string().optional() }).strict().describe(
|
|
580
|
+
"Add an EMPTY track of a given family (video|audio|image|overlay|effect). Optional pinned `id`."
|
|
581
|
+
),
|
|
582
|
+
z.object({ type: z.literal("removeTrack"), trackId: z.string() }).strict().describe(
|
|
583
|
+
"Remove a track AND all its clips by id."
|
|
584
|
+
),
|
|
585
|
+
z.object({ type: z.literal("updateTrack"), trackId: z.string(), updates: Track.pick({ name: true, enabled: true, volume: true }).partial() }).strict().describe(
|
|
586
|
+
"Patch a track's `name` / `enabled` by id."
|
|
587
|
+
),
|
|
588
|
+
z.object({ type: z.literal("reorderTracks"), fromIndex: z.number(), toIndex: z.number() }).strict().describe(
|
|
589
|
+
"Move a track from one index to another (changes layer/compositing order)."
|
|
590
|
+
),
|
|
591
|
+
z.object({ type: z.literal("moveClipToTrack"), clipId: z.string(), targetTrackId: z.string(), newStartTime: z.number().optional() }).strict().describe(
|
|
592
|
+
"Move a clip to another SAME-family track, optionally at a new `newStartTime`."
|
|
593
|
+
),
|
|
594
|
+
z.object({ type: z.literal("duplicateClip"), clipId: z.string(), newClipId: z.string().optional() }).strict().describe(
|
|
595
|
+
"Duplicate a clip by id. Pin `newClipId` to make the copy's id deterministic (required for a clean undo/inverse)."
|
|
596
|
+
),
|
|
597
|
+
z.object({ type: z.literal("cutAndRipple"), start: z.number(), end: z.number() }).strict().describe(
|
|
598
|
+
"Server-authoritative: delete the [start,end] time window (seconds) and ripple every downstream clip/marker/caption earlier to close the gap."
|
|
599
|
+
),
|
|
600
|
+
z.object({ type: z.literal("ripple"), time: z.number(), amount: z.number() }).strict().describe(
|
|
601
|
+
"Server-authoritative: shift everything at/after `time` (seconds) by `amount` seconds (+ opens a gap, \u2212 closes one)."
|
|
602
|
+
),
|
|
603
|
+
z.object({ type: z.literal("addExcludedRange"), clipId: z.string(), sourceStart: z.number(), sourceEnd: z.number(), reason: z.string().optional() }).strict().describe(
|
|
604
|
+
"Server-authoritative: exclude a [sourceStart,sourceEnd] span (seconds) of a clip's SOURCE (an internal trim) and ripple downstream \u2014 the preferred way to drop a sub-range vs a source patch."
|
|
605
|
+
),
|
|
606
|
+
z.object({ type: z.literal("removeExcludedRange"), clipId: z.string(), rangeIdx: z.number() }).strict().describe(
|
|
607
|
+
"Server-authoritative: remove a clip's previously-added excluded range by index (re-includes that span, ripples downstream)."
|
|
608
|
+
)
|
|
609
|
+
]).describe(
|
|
610
|
+
"One scoped composition operation. Discriminated by `type` \u2014 `clip.add` / `clip.remove` / `clip.update` patch clips across any family; the rest cover markers, reframe, effects, captions, format, tracks, and the server-authoritative ripple recomputes. Every variant is `.strict()`: an unknown field is refused, not ignored."
|
|
611
|
+
);
|
|
556
612
|
function mergedCaptionStyle(composition, patch) {
|
|
557
613
|
const existing = composition.captions?.style ?? {};
|
|
558
614
|
if (!patch) return existing;
|
package/dist/mcp/adapter.js
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
querySchemaShape,
|
|
3
3
|
serializeQuery,
|
|
4
4
|
waitForJob
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-EDR75OU7.js";
|
|
6
6
|
import {
|
|
7
7
|
CURATED_TOOLS
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-3OOMVQ6I.js";
|
|
9
9
|
import {
|
|
10
10
|
apiErrorFrom,
|
|
11
11
|
bodySchemaFor,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
opById,
|
|
17
17
|
safeParse,
|
|
18
18
|
sniffImageMediaType
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-RGKDDR7H.js";
|
|
20
20
|
import "../chunk-2ESYSVXG.js";
|
|
21
21
|
|
|
22
22
|
// ../mcp/src/adapter.ts
|
package/dist/mcp/core.js
CHANGED
|
@@ -16,8 +16,9 @@ import {
|
|
|
16
16
|
sniffAudioMediaType,
|
|
17
17
|
sniffImageMediaType,
|
|
18
18
|
text,
|
|
19
|
+
textWithData,
|
|
19
20
|
withMedia
|
|
20
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-RGKDDR7H.js";
|
|
21
22
|
import "../chunk-2ESYSVXG.js";
|
|
22
23
|
export {
|
|
23
24
|
__resetPreviewCache,
|
|
@@ -37,5 +38,6 @@ export {
|
|
|
37
38
|
sniffAudioMediaType,
|
|
38
39
|
sniffImageMediaType,
|
|
39
40
|
text,
|
|
41
|
+
textWithData,
|
|
40
42
|
withMedia
|
|
41
43
|
};
|
package/dist/mcp/curation.js
CHANGED
package/dist/mcp/server.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
registerRawTools,
|
|
8
8
|
registerSkillPrompts,
|
|
9
9
|
titleCase
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-LPFVUT3S.js";
|
|
11
|
+
import "../chunk-EDR75OU7.js";
|
|
12
|
+
import "../chunk-3OOMVQ6I.js";
|
|
13
|
+
import "../chunk-RGKDDR7H.js";
|
|
14
14
|
import "../chunk-2ESYSVXG.js";
|
|
15
15
|
export {
|
|
16
16
|
RAW_EXCLUDED_OPERATION_IDS,
|
package/dist/mcp.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
buildServer,
|
|
8
8
|
registerCuratedTools,
|
|
9
9
|
registerRawTools
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-LPFVUT3S.js";
|
|
11
|
+
import "./chunk-EDR75OU7.js";
|
|
12
|
+
import "./chunk-3OOMVQ6I.js";
|
|
13
|
+
import "./chunk-RGKDDR7H.js";
|
|
14
14
|
import "./chunk-2ESYSVXG.js";
|
|
15
15
|
export {
|
|
16
16
|
API_URLS,
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
Vignette,
|
|
13
13
|
catalog,
|
|
14
14
|
laneDepths
|
|
15
|
-
} from "../chunk-
|
|
16
|
-
import "../chunk-MFHXCHRI.js";
|
|
15
|
+
} from "../chunk-AMKPFIF4.js";
|
|
17
16
|
import "../chunk-XHGZ2E77.js";
|
|
17
|
+
import "../chunk-MFHXCHRI.js";
|
|
18
18
|
import "../chunk-W2245F6G.js";
|
|
19
19
|
import "../chunk-DEDZKZ6G.js";
|
|
20
20
|
import "../chunk-TZ7DKL2G.js";
|
|
@@ -30,14 +30,14 @@ import {
|
|
|
30
30
|
VisualDocsSnippet,
|
|
31
31
|
VoiceWaveform,
|
|
32
32
|
catalog
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-A76GTLSA.js";
|
|
34
34
|
import {
|
|
35
35
|
DashboardPopulate
|
|
36
36
|
} from "../chunk-S5H6GH6M.js";
|
|
37
|
-
import "../chunk-QAGGJHAF.js";
|
|
38
37
|
import "../chunk-LT4PWSR2.js";
|
|
39
38
|
import "../chunk-FWSJLHSV.js";
|
|
40
39
|
import "../chunk-XHGZ2E77.js";
|
|
40
|
+
import "../chunk-QAGGJHAF.js";
|
|
41
41
|
import "../chunk-W2245F6G.js";
|
|
42
42
|
import "../chunk-2ESYSVXG.js";
|
|
43
43
|
export {
|
package/dist/primitives.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
catalog as catalog4
|
|
3
|
-
} from "./chunk-YV5AYMNK.js";
|
|
4
1
|
import {
|
|
5
2
|
catalog as catalog7
|
|
6
3
|
} from "./chunk-PRSRV7AT.js";
|
|
@@ -15,23 +12,26 @@ import {
|
|
|
15
12
|
import "./chunk-QGAWDLYX.js";
|
|
16
13
|
import {
|
|
17
14
|
catalog as catalog6
|
|
18
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-A76GTLSA.js";
|
|
19
16
|
import "./chunk-S5H6GH6M.js";
|
|
20
|
-
import "./chunk-QAGGJHAF.js";
|
|
21
17
|
import {
|
|
22
18
|
catalog as catalog5
|
|
23
19
|
} from "./chunk-RAXHCRVV.js";
|
|
24
20
|
import {
|
|
25
21
|
catalog as catalog2
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import "./chunk-MFHXCHRI.js";
|
|
22
|
+
} from "./chunk-AMKPFIF4.js";
|
|
28
23
|
import {
|
|
29
24
|
catalog as catalog8
|
|
30
25
|
} from "./chunk-RL5SO653.js";
|
|
31
26
|
import "./chunk-LT4PWSR2.js";
|
|
32
27
|
import "./chunk-FWSJLHSV.js";
|
|
33
28
|
import "./chunk-ZFEXATWN.js";
|
|
29
|
+
import {
|
|
30
|
+
catalog as catalog4
|
|
31
|
+
} from "./chunk-YV5AYMNK.js";
|
|
34
32
|
import "./chunk-XHGZ2E77.js";
|
|
33
|
+
import "./chunk-QAGGJHAF.js";
|
|
34
|
+
import "./chunk-MFHXCHRI.js";
|
|
35
35
|
import "./chunk-W2245F6G.js";
|
|
36
36
|
import "./chunk-DEDZKZ6G.js";
|
|
37
37
|
import "./chunk-TZ7DKL2G.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cueframe/kernel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Publish-only aggregate of CueFrame's isomorphic kernel packages — composition, primitives, authoring, MCP, and friends shipped as one npm artifact. Members remain separate workspace packages; this only changes what ships.",
|
|
6
6
|
"files": [
|
|
@@ -17,25 +17,25 @@
|
|
|
17
17
|
"tsup": "^8.3.5",
|
|
18
18
|
"typescript": "^5.9.3",
|
|
19
19
|
"@cueframe/account-model": "0.1.0",
|
|
20
|
-
"@cueframe/animate": "0.1.0",
|
|
21
|
-
"@cueframe/cloud-import": "0.1.0",
|
|
22
20
|
"@cueframe/brand-derivation": "0.1.0",
|
|
23
21
|
"@cueframe/authoring": "0.1.0",
|
|
24
|
-
"@cueframe/
|
|
22
|
+
"@cueframe/animate": "0.1.0",
|
|
23
|
+
"@cueframe/cloud-import": "0.1.0",
|
|
25
24
|
"@cueframe/compose": "0.1.0",
|
|
26
|
-
"@cueframe/core": "0.1.0",
|
|
27
25
|
"@cueframe/component-runtime": "0.1.0",
|
|
28
|
-
"@cueframe/
|
|
29
|
-
"@cueframe/
|
|
30
|
-
"@cueframe/composition-ops": "0.1.0",
|
|
26
|
+
"@cueframe/composition": "0.1.0",
|
|
27
|
+
"@cueframe/core": "0.1.0",
|
|
31
28
|
"@cueframe/foundation": "0.1.0",
|
|
29
|
+
"@cueframe/director": "0.1.0",
|
|
30
|
+
"@cueframe/errors": "0.1.0",
|
|
31
|
+
"@cueframe/media-model": "0.1.0",
|
|
32
|
+
"@cueframe/perception": "0.1.0",
|
|
32
33
|
"@cueframe/plane": "0.1.0",
|
|
33
34
|
"@cueframe/nle-export": "0.1.0",
|
|
34
35
|
"@cueframe/mcp": "0.1.0",
|
|
35
|
-
"@cueframe/media-model": "0.1.0",
|
|
36
36
|
"@cueframe/render-harness": "0.1.0",
|
|
37
|
-
"@cueframe/
|
|
38
|
-
"@cueframe/
|
|
37
|
+
"@cueframe/primitives": "0.1.0",
|
|
38
|
+
"@cueframe/composition-ops": "0.1.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"gsap": "3.13.0",
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DashboardPopulate
|
|
3
3
|
} from "./chunk-S5H6GH6M.js";
|
|
4
|
-
import {
|
|
5
|
-
useFrameScale
|
|
6
|
-
} from "./chunk-QAGGJHAF.js";
|
|
7
4
|
import {
|
|
8
5
|
resolveTypeface
|
|
9
6
|
} from "./chunk-LT4PWSR2.js";
|
|
@@ -14,6 +11,9 @@ import {
|
|
|
14
11
|
FitText,
|
|
15
12
|
resolveFitFontSize
|
|
16
13
|
} from "./chunk-XHGZ2E77.js";
|
|
14
|
+
import {
|
|
15
|
+
useFrameScale
|
|
16
|
+
} from "./chunk-QAGGJHAF.js";
|
|
17
17
|
import {
|
|
18
18
|
ACCENT,
|
|
19
19
|
ACCENT_DEEP,
|