cueframe 0.9.4 → 0.11.3

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 (51) hide show
  1. package/README.md +39 -30
  2. package/dist/analyze-C3MSCON6.js +2 -0
  3. package/dist/chunk-OAJBHFAJ.js +18 -0
  4. package/dist/cueframe.js +55 -54
  5. package/dist/skills/add-music-bed/SKILL.md +5 -23
  6. package/dist/skills/brand-reel/SKILL.md +5 -28
  7. package/dist/skills/clip-a-talking-head/SKILL.md +2 -20
  8. package/dist/skills/composing-video/SKILL.md +36 -424
  9. package/dist/skills/composing-video/references/acceptance-template.md +21 -0
  10. package/dist/skills/composing-video/references/audio-design.md +125 -0
  11. package/dist/skills/composing-video/references/card-and-motion-runtime.md +49 -0
  12. package/dist/skills/composing-video/references/craft-principles.md +25 -0
  13. package/dist/skills/composing-video/references/film-planning.md +37 -0
  14. package/dist/skills/composing-video/references/format-decisions.md +17 -0
  15. package/dist/skills/composing-video/references/format-playbooks.md +96 -0
  16. package/dist/skills/composing-video/references/motion-design.md +25 -0
  17. package/dist/skills/composing-video/references/project-policy.md +18 -0
  18. package/dist/skills/composing-video/references/sfx-pack.md +69 -0
  19. package/dist/skills/composing-video/references/sound-and-timing.md +15 -0
  20. package/dist/skills/composing-video/references/tool-map.md +43 -0
  21. package/dist/skills/cueframe-brand-demo/SKILL.md +2 -8
  22. package/dist/skills/cueframe-cli/SKILL.md +73 -59
  23. package/dist/skills/cueframe-component-authoring/SKILL.md +20 -169
  24. package/dist/skills/cueframe-component-authoring/references/authoring-paths.md +72 -0
  25. package/dist/skills/cueframe-component-authoring/references/forking-and-layout.md +35 -0
  26. package/dist/skills/cueframe-component-authoring/references/native-component-workflows.md +98 -0
  27. package/dist/skills/cueframe-component-authoring/references/native-source-contract.md +54 -0
  28. package/dist/skills/cueframe-component-authoring/references/parented-device-card.json +13 -0
  29. package/dist/skills/cueframe-component-authoring/references/parented-motion.md +25 -0
  30. package/dist/skills/cueframe-component-authoring/references/retired-projects.md +26 -0
  31. package/dist/skills/cueframe-compose-loop/SKILL.md +14 -112
  32. package/dist/skills/cueframe-compose-loop/references/convergence-loop.md +128 -0
  33. package/dist/skills/cueframe-compose-loop/references/preview-workflow.md +7 -3
  34. package/dist/skills/cueframe-connect/SKILL.md +4 -9
  35. package/dist/skills/cueframe-connect/references/tools.md +146 -0
  36. package/dist/skills/cueframe-product-video/SKILL.md +9 -14
  37. package/dist/skills/cueframe-reference-video/SKILL.md +30 -0
  38. package/dist/skills/cueframe-reference-video/references/measurement-and-comparison.md +45 -0
  39. package/dist/skills/cueframe-reference-video/scripts/motion-grid.sh +116 -0
  40. package/dist/skills/cueframe-scene-shot/SKILL.md +2 -8
  41. package/dist/skills/cueframe-storyboard/SKILL.md +1 -7
  42. package/dist/skills/every-format-from-one-edit/SKILL.md +3 -19
  43. package/dist/skills/extracting-brand-kits/SKILL.md +1 -7
  44. package/dist/skills/launch-video/SKILL.md +6 -26
  45. package/dist/skills/make-a-social-reel/SKILL.md +7 -26
  46. package/dist/skills/rebrand-a-video/SKILL.md +2 -19
  47. package/dist/skills/video-craft-standards/SKILL.md +20 -103
  48. package/dist/skills/video-craft-standards/references/format-standards.md +118 -0
  49. package/package.json +12 -11
  50. package/dist/analyze-XP2BESVX.js +0 -2
  51. package/dist/chunk-RSOHINDT.js +0 -18
@@ -5,13 +5,7 @@ description: Turns footage into a finished 9:16 social reel — hook inside 2 se
5
5
 
6
6
  # Make a social reel
7
7
 
8
- ## Scope and capability policy
9
-
10
- User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
11
-
12
- Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
13
-
14
- For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
8
+ Use the [project and capability policy](../composing-video/references/project-policy.md) for scope, current state and metered work.
15
9
 
16
10
  You hand over footage (a file URL, a talk, a product moment); you get back a 9:16 reel of 8–30
17
11
  seconds that opens on its strongest image, cuts on the music, carries brand-grade type, and ends
@@ -74,29 +68,16 @@ affected window and regressions without automatically rerunning the full-film ju
74
68
  `describe_composition_ops({type:"captions.fromComposition"})`, then style via
75
69
  `setCaptionStyle` (plated, bottom, out of the mouth/eyes). Most social viewing is sound-off;
76
70
  don't karaoke a beat with no speech.
77
- 8. **Look, then get judged.** `preview_frame` at t=0, hook-end, and every beat boundary;
78
- describe each still in words before scoring it. Then `score_composition` with your one-line
79
- vision as `editorialIntent` — fix the worst criterion first. Meet the applicable acceptance criteria; budget
80
- up to 3–5 passes only for broader review.
81
- 9. **One final render.** `create_render` → `wait_job (kind:"render")`. Iterate with previews,
71
+ 8. **Inspect and revise.** `preview_frame` at the important layout and transition landmarks;
72
+ describe each still in words, then inspect the intervening motion and relevant audio. Use
73
+ `score_composition` only when broader critique is useful and within budget, with your one-line
74
+ vision as `editorialIntent`, and fix the worst criterion first. Fix located acceptance failures against the brief.
75
+ 9. **Export for requested final delivery.** `create_render` → `wait_job (kind:"render")`. Iterate with previews,
82
76
  not renders.
83
77
 
84
78
  ## What good looks like
85
79
 
86
- Quoted from `video-craft-standards` §1 (Social reel) — these are defaults for this format, subject to the scope policy above:
87
-
88
- > **DEFAULT** The hook lands inside 2 seconds: the strongest image, motion, or claim opens the
89
- > piece. No logo-first cold opens, no fade-in-from-black preambles.
90
-
91
- > **DEFAULT** Typography is poster-grade: composed plates/fields in the brand palette, considered
92
- > alignment and scale. **Consider:** centered white text floating on footage.
93
-
94
- > **DEFAULT** Pacing is cut-driven: a new visual beat at least every ~4s […] **DEFAULT** Ends on a
95
- > deliberate beat: tagline, logo, or CTA lockup — not a clip running out.
96
-
97
- And the cross-cutting audio rule:
98
-
99
- > **DEFAULT** Audio is decided, never defaulted […] **Consider:** a render whose silence nobody chose.
80
+ Use the relevant [craft review questions](../video-craft-standards/SKILL.md) and the [preview workflow](../cueframe-compose-loop/references/preview-workflow.md). Judge the brief's actual intent, visual relationships, timing and sound; format suggestions do not override the requested treatment. For this format's defaults read section 1 (Social reel) of the [format standards](../video-craft-standards/references/format-standards.md).
100
81
 
101
82
  ## Delivering
102
83
 
@@ -5,13 +5,7 @@ description: Swaps the brand kit under an existing video and re-renders — toke
5
5
 
6
6
  # Rebrand a video
7
7
 
8
- ## Scope and capability policy
9
-
10
- User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
11
-
12
- Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
13
-
14
- For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
8
+ Use the [project and capability policy](../composing-video/references/project-policy.md) for scope, current state and metered work.
15
9
 
16
10
  You bring a finished video and a new brand (a kit, a website, or new colors/fonts/logo); you get
17
11
  the same video back wearing the new identity — everything bound to brand tokens re-themes at
@@ -72,18 +66,7 @@ keep the final re-render separate from previews used to resolve individual styli
72
66
 
73
67
  ## What good looks like
74
68
 
75
- Quoted from `video-craft-standards` §3 (Brand-identity reel) — the bespoke test applies to every
76
- card in any class:
77
-
78
- > **DEFAULT** Every graphic is bespoke to the brand: its type, its palette as fields, its layout
79
- > system. **Consider:** any layout that would look correct with another brand's hex swapped in.
80
-
81
- > **DEFAULT** Footage color and brand palette agree — grade toward the palette or choose footage
82
- > that lives in it.
83
-
84
- And cross-cutting: *"**DEFAULT** Brand/text graphics are AUTHORED — `kind:"card"` HTML (your
85
- typography, layout, palette-as-fields) […] **Consider:** a brand graphic rendered from a catalog text
86
- primitive."*
69
+ Use the relevant [craft review questions](../video-craft-standards/SKILL.md) and the [preview workflow](../cueframe-compose-loop/references/preview-workflow.md). Judge the brief's actual intent, visual relationships, timing and sound; format suggestions do not override the requested treatment. The bespoke test in section 3 of the [format standards](../video-craft-standards/references/format-standards.md) applies to every card in any class.
87
70
 
88
71
  ## Delivering
89
72
 
@@ -1,121 +1,38 @@
1
1
  ---
2
2
  name: video-craft-standards
3
- description: Craft defaults and applicable review checklists for CueFrame videos (social reel, launch film, brand reel, talking-head clip). User intent and requested scope govern their application; factual fidelity and tool contracts remain mandatory. Triggers on "is this good enough", "quality bar", "what should a finished reel have", "review my video", or any request to make a video when no other skill has stated the bar.
3
+ description: "Use when judging whether a CueFrame video's idea, visual form, motion, timing and sound meet its brief or reference (social reel, launch film, brand reel, talking-head clip). For tool selection and scoped revision use cueframe-compose-loop. Triggers on \"is this good enough\", \"quality bar\", \"what should a finished reel have\", \"review my video\", or any request to make a video when no other skill has stated the bar."
4
4
  ---
5
5
 
6
- # Video-Craft Standards — what "finished" means
6
+ # Video craft review
7
7
 
8
- ## Scope and capability policy
8
+ Use the [project and capability policy](../composing-video/references/project-policy.md). Judge the requested film, not a universal house style. Typography, gradients, logo openings, deliberate stillness, silent work and reconstructed UI artwork can all be valid choices. Factual claims and the identity of actual captures must remain truthful.
9
9
 
10
- User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
10
+ [cueframe-compose-loop](../cueframe-compose-loop/SKILL.md) owns evidence, optional judge use and revision scope. Its [preview workflow](../cueframe-compose-loop/references/preview-workflow.md) distinguishes isolated previews, saved compositions and final exports. Use these questions where they matter to the brief; a small color correction does not require a new whole-film critique.
11
11
 
12
- Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
12
+ ## What should the viewer experience?
13
13
 
14
- For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
14
+ Can the film's intended idea, transformation, mood or observation be understood? Does each major choice support it? For a story, does an action change what follows? For an identity study, are form and movement specific to that identity? A film can intentionally be non-narrative; do not invent a sales argument to justify it.
15
15
 
16
- These are aesthetic defaults for the named formats, not universal delivery gates. Apply only the checklist items relevant to the requested artifact; a silent typography study needs neither footage nor narration, and a title correction needs only affected evidence. User acceptance criteria govern delivery. The labels below describe recommendations; do not reject explicit creative choices using a default or a judge score.
16
+ ## Do the visual relationships hold?
17
17
 
18
- ## The controlling idea — the rule above every rule
18
+ Inspect hierarchy, silhouette, spacing and legibility at the intended viewing size. Verify that essential copy has enough readable time after settling. For a reference, compare projected bounds, glyph form, angles, materials and camera path as well as subject names. Two scenes showing the same phone are not necessarily the same shot.
19
19
 
20
- - **DEFAULT** For new work, consider stating the video's CLAIM in one sentence —
21
- the thing a viewer should be able to repeat afterward ("real bread takes
22
- 48 hours and you can taste every one of them"). Not a vibe, not a tagline:
23
- a claim with tension (what does this brand/story believe that its category
24
- doesn't?).
25
- - **DEFAULT** Each included channel serves the requested intent, in harmony:
26
- - **Footage** — each clip earns its place as proof of the claim, chosen
27
- from the claim's shot list, not from search-term aesthetics.
28
- - **Sound** — the bed's mood and TEMPO embody the claim (a "slow" claim
29
- gets a patient, sparse bed and the nerve to hold shots; an "instant"
30
- claim cuts hot). Silence and pauses are rhetoric, not absence.
31
- - **Pacing** — the cut rhythm IS part of the argument; it may defy
32
- platform convention when the claim demands it.
33
- - **Type/cards** — copy advances the argument; the tagline lands as the
34
- CONCLUSION the beats have earned, never as a caption.
35
- - **Review prompts:** (1) beats reorderable without changing what the video
36
- says; (2) any channel (bed, shot, card) that would fit a different claim
37
- equally well; (3) a viewer who watched it cannot state the claim.
20
+ Mounted UI should remain attached to its screen. Masks, edges and occlusion should agree with the pose. A pointer contacts the intended control before the response; an object carried through a transition retains identity and an intelligible path. Multiple simultaneous movements are useful when the viewer can follow their relationship. An attractive still does not establish any of these temporal properties.
38
21
 
39
- ## Cross-cutting rules (every artifact)
22
+ ## Does time express the idea?
40
23
 
41
- These are final-artifact criteria, not a requirement to re-plan or export after every tweak.
42
- For scoped corrections and preview selection, use `cueframe-compose-loop`'s
43
- [preview workflow](../cueframe-compose-loop/references/preview-workflow.md). Inspect continuous
44
- motion and listen to affected audio, not only stills or judge scores. Keep the user's explicit
45
- scope and acceptance criteria; approved simulated UI is not evidence of a real product capture.
24
+ Look for accidental pauses, rushed reading windows, unexplained changes in speed and transitions that lose the subject. A deliberate hold can be the strongest beat. Check actual stable time rather than a layer's nominal duration. For a revision, ensure dependent motion and sound still agree with the new event order. Inspect the complete end, including backgrounds, captions and tails.
46
25
 
47
- - **DEFAULT** Brand/text graphics are AUTHORED — `kind:"card"` HTML (your
48
- typography, layout, palette-as-fields) animated in CSS or with `clip.setKeyframes`,
49
- or a native component (`create_component`). Catalog text primitives are for utility only.
50
- **Consider:** a brand graphic rendered from a catalog text primitive.
51
- - **DEFAULT** Audio is decided, never defaulted: a music bed (curated packs via
52
- `import_resource {kind:"music-pack"}`) or ambience/loops (Freesound via
53
- `search_resources kind:"sfx"`), honoring the brand kit's `musicMood`;
54
- cut to the beat via `materializeGrid` when the bed drives pacing — OR an
55
- explicit intentional-silence decision recorded in your delivery note with
56
- the reason. **Consider:** a render whose silence nobody chose.
57
- - **DEFAULT** Footage carries the video: real footage / real UI / real data
58
- ≥60% of runtime for footage-first classes. Typography-only work is a valid requested format.
59
- - **DEFAULT** Every stock asset's provenance is recorded (provider, id, author).
60
- - **DEFAULT** Safe-area respected: no critical copy in the outer ~8% of frame.
61
- - **DEFAULT** One final render per approval; iterate with previews, not renders.
62
- - **DEFAULT** Delivery never ends with "done": the last message carries the
63
- output link and where to find it, plus the intentional-silence note if any.
26
+ ## Does the medium support the promise?
64
27
 
65
- ## 1. Social reel — 9:16 · 8–30s
28
+ - **Product evidence:** a real interaction and its result are visible and legible. Simulated UI is identified as artwork, not a capture of working software.
29
+ - **Speech-led footage:** selected words preserve meaning; captions and framing follow actual source evidence and the saved edit. Camera movement and captions are choices governed by the brief.
30
+ - **Type, illustration or data:** geometry and transformation carry meaning; text remains accurate, values are sourced and material behavior is coherent.
31
+ - **Brand work:** type, palette, material and motion form an intentional system; a new logo/name should not be the only thing distinguishing a supposedly specific treatment.
32
+ - **Sound:** heard intelligibility, balance and event synchronization are separate from loudness or waveform measurements. Silence needs no apology when it serves the piece.
66
33
 
67
- - **DEFAULT** The hook lands inside 2 seconds: the strongest image, motion,
68
- or claim opens the piece. No logo-first cold opens, no fade-in-from-black
69
- preambles.
70
- - **DEFAULT** Typography is poster-grade: composed plates/fields in the brand
71
- palette, considered alignment and scale. **Consider:** centered white text
72
- floating on footage.
73
- - **DEFAULT** Pacing is cut-driven: a new visual beat at least every ~4s; static
74
- holds >4s need motion inside the frame (reframe push, kenBurns, animated
75
- card) or they die.
76
- - **DEFAULT** Ends on a deliberate beat: tagline, logo, or CTA lockup — not a
77
- clip running out.
78
- - **SHOULD** Cuts land on the music grid when a bed exists.
34
+ A useful critique names a timestamp/window, observed problem, its consequence and a plausible correction. Prioritize failures of intent, fidelity or continuity over minor polish. Do not certify unseen motion or unheard audio, and do not substitute a score for the user's acceptance criteria.
79
35
 
80
- ## 2. Launch film / feature announcement — 16:9 · 30–90s
36
+ ## Detailed guidance
81
37
 
82
- - **DEFAULT** Payoff-first hook: the OUTCOME, not the feature name
83
- ("Close the books two days faster" beats "Introducing the reconciliation
84
- module"). No throat-clearing ("in this video we're going to…").
85
- - **DEFAULT** Narration or a bed that builds toward the reveal; pacing tightens
86
- as the payoff approaches.
87
- - **DEFAULT** Real product surface: actual UI/screens/output — never mocked.
88
- - **DEFAULT** End card with a single CTA.
89
- - **DEFAULT** Captions present when narrated.
90
-
91
- ## 3. Brand-identity reel — 9:16 · 12–20s (the showcase class)
92
-
93
- Everything in §1, plus:
94
- - **DEFAULT** Three-beat arc: opening brand moment (wordmark treatment) →
95
- middle craft/proof beat (the subject's world, with an editorial device —
96
- numbered chapter, pull-quote, stat) → closing tagline lockup.
97
- - **DEFAULT** Every graphic is bespoke to the brand: its type, its palette as
98
- fields, its layout system. **Consider:** any layout that would look correct with
99
- another brand's hex swapped in.
100
- - **DEFAULT** Footage color and brand palette agree — grade toward the palette
101
- or choose footage that lives in it.
102
-
103
- ## 4. Talking-head clip — any aspect · 15–60s
104
-
105
- - **DEFAULT** Hook = the strongest sentence, first. Cut TO the moment;
106
- never open on wind-up.
107
- - **DEFAULT** Active-speaker reframe (`focus: active-speaker` / `face`) — a
108
- moving camera, not a static center crop.
109
- - **DEFAULT** Captions timed to the saved edited timeline (`captions.fromComposition`
110
- after the clip edits; re-run after later edits). Speech clips must have saved duration matching playable source duration divided by
111
- playbackRate.
112
- The focused behind-the-speaker LOOK is an overlay text layer at
113
- `zPlane:"behind-subject"` where the footage allows. Use caption-layer
114
- `zPlane:"behind-subject"` only when the user explicitly wants every running
115
- caption behind the speaker and the legibility gate accepts it.
116
- - **DEFAULT** Dead air and false starts cut (`addExcludedRange` /
117
- `cutAndRipple`).
118
-
119
- ## Scoring discipline
120
-
121
- Check the requested criteria against appropriate real evidence: affected stills, continuous motion and audio when relevant. Broader review can use `score_composition` when useful and within budget; it is not mandatory for a scoped correction. The hosted judge includes a fixed caption criterion and can penalize intentionally uncaptioned work; do not add captions solely to improve that score. These skill changes do not change judge behavior. Failed user acceptance criteria remain failures regardless of score. Stop and report remaining gaps after two passes without improvement; export only for requested final delivery.
38
+ [Format standards](references/format-standards.md) has the controlling idea, the cross-cutting rules, and the checklists for social reels, launch films, brand-identity reels and talking-head clips, plus scoring discipline.
@@ -0,0 +1,118 @@
1
+ # Format standards
2
+
3
+ Defaults, examples and detail for this topic. The [skill](../SKILL.md) and the [project and capability policy](../../composing-video/references/project-policy.md) take precedence where they differ, and the current tool schemas are authoritative.
4
+
5
+ ## Scope and capability policy
6
+
7
+ User intent and acceptance criteria override this recipe's aesthetic defaults. Silent, typography-only, uncaptioned and slow work are valid; no universal narration, footage, CTA, beat count or score target. Contracts, factual fidelity, media bindings and current source revisions remain mandatory.
8
+
9
+ Read available tools and current project; preserve the chosen local/hosted lane. Supported local work needs no hosted registration. Do not silently install, authenticate, switch projects or upload local content. Before metered hosted work, check `get_account`, entitlements, balance and quotes. Desktop setup: https://docs.cueframe.ai.
10
+
11
+ For scoped revisions, preserve unrelated timing, media, audio and shared brand-kit state. Edit affected content; inspect relevant frames, continuous motion and affected audio. No restarted intake, new approval pause, paid judge or final export by default. Judge only when useful; scores never override acceptance failures. Stop/report after two no-improvement passes. See [preview workflow](../../cueframe-compose-loop/references/preview-workflow.md).
12
+
13
+ These are aesthetic defaults for the named formats, not universal delivery gates. Apply only the checklist items relevant to the requested artifact; a silent typography study needs neither footage nor narration, and a title correction needs only affected evidence. User acceptance criteria govern delivery. The labels below describe recommendations; do not reject explicit creative choices using a default or a judge score.
14
+
15
+ ## The controlling idea — the rule above every rule
16
+
17
+ - **DEFAULT** For new work, consider stating the video's CLAIM in one sentence —
18
+ the thing a viewer should be able to repeat afterward ("real bread takes
19
+ 48 hours and you can taste every one of them"). Not a vibe, not a tagline:
20
+ a claim with tension (what does this brand/story believe that its category
21
+ doesn't?).
22
+ - **DEFAULT** Each included channel serves the requested intent, in harmony:
23
+ - **Footage** — each clip earns its place as proof of the claim, chosen
24
+ from the claim's shot list, not from search-term aesthetics.
25
+ - **Sound** — the bed's mood and TEMPO embody the claim (a "slow" claim
26
+ gets a patient, sparse bed and the nerve to hold shots; an "instant"
27
+ claim cuts hot). Silence and pauses are rhetoric, not absence.
28
+ - **Pacing** — the cut rhythm IS part of the argument; it may defy
29
+ platform convention when the claim demands it.
30
+ - **Type/cards** — copy advances the argument; the tagline lands as the
31
+ CONCLUSION the beats have earned, never as a caption.
32
+ - **Review prompts:** (1) beats reorderable without changing what the video
33
+ says; (2) any channel (bed, shot, card) that would fit a different claim
34
+ equally well; (3) a viewer who watched it cannot state the claim.
35
+
36
+ ## Cross-cutting rules (every artifact)
37
+
38
+ These are final-artifact criteria, not a requirement to re-plan or export after every tweak.
39
+ For scoped corrections and preview selection, use `cueframe-compose-loop`'s
40
+ [preview workflow](../../cueframe-compose-loop/references/preview-workflow.md). Inspect continuous
41
+ motion and listen to affected audio, not only stills or judge scores. Keep the user's explicit
42
+ scope and acceptance criteria; approved simulated UI is not evidence of a real product capture.
43
+
44
+ - **DEFAULT** Brand/text graphics are AUTHORED — `kind:"card"` HTML (your
45
+ typography, layout, palette-as-fields) animated in CSS or with `clip.setKeyframes`,
46
+ or a native component (`create_component`). Catalog text primitives are for utility only.
47
+ **Consider:** a brand graphic rendered from a catalog text primitive.
48
+ - **DEFAULT** Audio is decided, never defaulted: a music bed (curated packs via
49
+ `import_resource {kind:"music-pack"}`) or ambience/loops (Freesound via
50
+ `search_resources kind:"sfx"`), honoring the brand kit's `musicMood`;
51
+ cut to the beat via `materializeGrid` when the bed drives pacing — OR an
52
+ explicit intentional-silence decision recorded in your delivery note with
53
+ the reason. **Consider:** a render whose silence nobody chose.
54
+ - **DEFAULT** Footage carries the video: real footage / real UI / real data
55
+ ≥60% of runtime for footage-first classes. Typography-only work is a valid requested format.
56
+ - **DEFAULT** Every stock asset's provenance is recorded (provider, id, author).
57
+ - **DEFAULT** Safe-area respected: no critical copy in the outer ~8% of frame.
58
+ - **DEFAULT** One final render per approval; iterate with previews, not renders.
59
+ - **DEFAULT** Delivery never ends with "done": the last message carries the
60
+ output link and where to find it, plus the intentional-silence note if any.
61
+
62
+ ## 1. Social reel — 9:16 · 8–30s
63
+
64
+ - **DEFAULT** The hook lands inside 2 seconds: the strongest image, motion,
65
+ or claim opens the piece. No logo-first cold opens, no fade-in-from-black
66
+ preambles.
67
+ - **DEFAULT** Typography is poster-grade: composed plates/fields in the brand
68
+ palette, considered alignment and scale. **Consider:** centered white text
69
+ floating on footage.
70
+ - **DEFAULT** Pacing is cut-driven: a new visual beat at least every ~4s; static
71
+ holds >4s need motion inside the frame (reframe push, kenBurns, animated
72
+ card) or they die.
73
+ - **DEFAULT** Ends on a deliberate beat: tagline, logo, or CTA lockup — not a
74
+ clip running out.
75
+ - **SHOULD** Cuts land on the music grid when a bed exists.
76
+
77
+ ## 2. Launch film / feature announcement — 16:9 · 30–90s
78
+
79
+ - **DEFAULT** Payoff-first hook: the OUTCOME, not the feature name
80
+ ("Close the books two days faster" beats "Introducing the reconciliation
81
+ module"). No throat-clearing ("in this video we're going to…").
82
+ - **DEFAULT** Narration or a bed that builds toward the reveal; pacing tightens
83
+ as the payoff approaches.
84
+ - **DEFAULT** Real product surface: actual UI/screens/output — never mocked.
85
+ - **DEFAULT** End card with a single CTA.
86
+ - **DEFAULT** Captions present when narrated.
87
+
88
+ ## 3. Brand-identity reel — 9:16 · 12–20s (the showcase class)
89
+
90
+ Everything in §1, plus:
91
+ - **DEFAULT** Three-beat arc: opening brand moment (wordmark treatment) →
92
+ middle craft/proof beat (the subject's world, with an editorial device —
93
+ numbered chapter, pull-quote, stat) → closing tagline lockup.
94
+ - **DEFAULT** Every graphic is bespoke to the brand: its type, its palette as
95
+ fields, its layout system. **Consider:** any layout that would look correct with
96
+ another brand's hex swapped in.
97
+ - **DEFAULT** Footage color and brand palette agree — grade toward the palette
98
+ or choose footage that lives in it.
99
+
100
+ ## 4. Talking-head clip — any aspect · 15–60s
101
+
102
+ - **DEFAULT** Hook = the strongest sentence, first. Cut TO the moment;
103
+ never open on wind-up.
104
+ - **DEFAULT** Active-speaker reframe (`focus: active-speaker` / `face`) — a
105
+ moving camera, not a static center crop.
106
+ - **DEFAULT** Captions timed to the saved edited timeline (`captions.fromComposition`
107
+ after the clip edits; re-run after later edits). Speech clips must have saved duration matching playable source duration divided by
108
+ playbackRate.
109
+ The focused behind-the-speaker LOOK is an overlay text layer at
110
+ `zPlane:"behind-subject"` where the footage allows. Use caption-layer
111
+ `zPlane:"behind-subject"` only when the user explicitly wants every running
112
+ caption behind the speaker and the legibility gate accepts it.
113
+ - **DEFAULT** Dead air and false starts cut (`addExcludedRange` /
114
+ `cutAndRipple`).
115
+
116
+ ## Scoring discipline
117
+
118
+ Check the requested criteria against appropriate real evidence: affected stills, continuous motion and audio when relevant. Broader review can use `score_composition` when useful and within budget; it is not mandatory for a scoped correction. The hosted judge includes a fixed caption criterion and can penalize intentionally uncaptioned work; do not add captions solely to improve that score. These skill changes do not change judge behavior. Failed user acceptance criteria remain failures regardless of score. Stop and report remaining gaps after two passes without improvement; export only for requested final delivery.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cueframe",
3
- "version": "0.9.4",
3
+ "version": "0.11.3",
4
4
  "description": "CueFrame video editing CLI: manage media, edit compositions and render MP4s from terminals and scripts.",
5
5
  "keywords": [
6
6
  "cueframe",
@@ -33,20 +33,21 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "add-mcp": "^2.4.0",
36
- "better-auth": "1.6.22",
37
- "commander": "^13.1.0",
38
- "open": "^10.1.0",
39
- "ora": "^8.2.0",
36
+ "better-auth": "1.7.7",
37
+ "commander": "^15.0.0",
38
+ "open": "^11.0.4",
39
+ "ora": "^9.4.1",
40
40
  "pino": "^10.3.1"
41
41
  },
42
42
  "devDependencies": {
43
- "zod": "^4.5.4",
44
- "@types/node": "^24.0.0",
43
+ "zod": "^4.6.7",
44
+ "@types/node": "^26.6.5",
45
45
  "tsup": "^8.5.1",
46
- "typescript": "^5.9.3",
47
- "vitest": "^4.1.2",
48
- "@cueframe/sdk": "^0.12.0",
49
- "@cueframe/skills": "0.3.2"
46
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
47
+ "vitest": "^5.0.3",
48
+ "@typescript/native": "npm:typescript@^7.0.2",
49
+ "@cueframe/sdk": "^0.16.1",
50
+ "@cueframe/skills": "0.4.5"
50
51
  },
51
52
  "repository": {
52
53
  "type": "git",
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{G as a}from"./chunk-RSOHINDT.js";import"./chunk-3QSA3EBY.js";export{a as analyzeCommand};
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as y}from"./chunk-3QSA3EBY.js";var u=class extends Error{status;code;details;requestId;constructor(t,r,n){super(r.message),this.name="ApiError",this.status=t,this.code=r.code,this.details=r.details,this.requestId=n}},v=class extends Error{url;timeoutMs;constructor(t,r){super(`Request timed out after ${r}ms: ${t}`),this.name="TimeoutError",this.url=t,this.timeoutMs=r}},q=class extends Error{url;constructor(t,r){super(`Request failed before a response: ${t}`,{cause:r}),this.name="NetworkError",this.url=t}},g={baseUrl:""};function O(e){return g={timeoutMs:3e4,...e},g}function I(){return g}function pt(e,t){return/^https?:\/\//.test(t)?t:e.replace(/\/$/,"")+(t.startsWith("/")?t:`/${t}`)}async function N(e,t={}){if(!g.baseUrl)throw new Error("@cueframe/sdk: createClient({baseUrl}) must be called before issuing requests.");let r=g.fetch??fetch,n=pt(g.baseUrl,e),o=new Headers({accept:"application/json"});for(let[c,d]of Object.entries(g.headers??{}))o.set(c,d);t.headers&&new Headers(t.headers).forEach((c,d)=>o.set(d,c)),g.apiKey&&!o.has("authorization")&&o.set("authorization",`Bearer ${g.apiKey}`);let s=g.timeoutMs??3e4,i=new AbortController,p=setTimeout(()=>i.abort(),s),m=t.signal?AbortSignal.any([t.signal,i.signal]):i.signal;try{let c=await r(n,{...t,headers:o,signal:m}),d={};c.headers.forEach((b,x)=>{d[x.toLowerCase()]=b});let l=null;if(c.status!==204)if((c.headers.get("content-type")??"").includes("application/json"))try{l=await c.json()}catch{l=null}else l=await c.text();return{status:c.status,statusText:c.statusText,headers:d,body:l,requestId:d["x-request-id"]}}catch(c){throw t.signal?.aborted?c:i.signal.aborted?new v(n,s):new q(n,c)}finally{clearTimeout(p)}}async function a(e,t={}){let r=await N(e,t);if(r.status>=400){let n;throw r.body&&typeof r.body=="object"&&"error"in r.body?n=r.body.error??{code:"unknown",message:r.statusText}:n={code:"unknown",message:r.statusText},new u(r.status,n,r.requestId)}if(r.status!==204)return r.body}var ct={unauthorized:"The credential is invalid or expired for this target, or it belongs to a different environment. Re-authenticate the way you connected: reconnect the MCP server, run `cueframe login` in a terminal, or supply a current API key.",forbidden:"The credential's permissions don't cover this operation. The server message above names the exact missing ones and the `permissions` body that grants them; a key's permissions are fixed at creation, so this needs a NEW key, not a change to this one.",not_found:"No such resource in this org (cross-org access also reads as 404). Check the id, or enumerate with the matching list command/tool.",media_not_ready:"Media is still processing. Wait for the `media.transcribed` webhook or retry after ~30s.",suggestions_already_complete:"Suggestions already exist for this media item. To re-run, call DELETE /v1/media/:id/suggestions first to reset state.",precondition_required:"Fetch the resource with GET first to obtain its ETag, then resend the write with `If-Match: <etag>`. `cueframe composition get` returns one for you.",stale_etag:"Resource was modified since your last GET \u2014 `details.currentEtag` is the value to thread next. Re-GET (or run `cueframe composition get`) and rebase your edits before retrying.",conflict:"ETag mismatch \u2014 the resource was modified since your last GET. Re-fetch and merge before retrying.",media_in_use:"Media is referenced by other resources. See `details.projectIds` and `details.sessionIds` \u2014 remove those references before deleting.",session_in_use:"Session is referenced by a composition. See `details.projectIds` \u2014 remove those references before deleting.",render_not_cancellable:"Render is already in a terminal state (complete / error / cancelled) and cannot be cancelled.",rate_limited:"Rate limit exceeded. Back off using the `retry-after` response header.",invalid_composition:"Composition violates an invariant (see `details`). Common ones: clip_source_track_kind_mismatch, track_clips_overlap, transition_no_predecessor.",clip_not_found:"The clip suggestion publicId doesn't exist in this org. Run `cueframe clips <mediaItemId>` to enumerate valid sug_* ids.",service_unavailable:"The processing pipeline is temporarily unavailable. Retry shortly; if it persists, contact support@cueframe.ai with the requestId.",payment_required:"The request exceeds a billing limit. For generation, the estimated cost is over the per-call ceiling (see `details.estimateUsd` / `details.ceilingUsd`) \u2014 lower the requested duration or raise the ceiling."};function j(e){return e instanceof u?ct[e.code]??null:null}async function*dt(e,t,r){let n=I();if(!n?.baseUrl)throw new Error(`@cueframe/sdk: createClient({baseUrl}) must be called before ${t}.`);let o=n.baseUrl.replace(/\/$/,"")+e,s=new Headers({accept:"text/event-stream",...n.headers??{}});n.apiKey&&!s.has("authorization")&&s.set("authorization",`Bearer ${n.apiKey}`);let p=await(n.fetch??fetch)(o,{method:"GET",headers:s,signal:r.signal});if(!p.ok){let l;try{l=(await p.json()).error??{code:"unknown",message:p.statusText}}catch{l={code:"unknown",message:p.statusText}}throw new u(p.status,l,p.headers.get("x-request-id")??void 0)}if(!p.body)throw new Error("SSE response has no body");let m=p.body.getReader(),c=new TextDecoder("utf-8"),d="";try{for(;;){let{value:l,done:b}=await m.read();if(b)break;d+=c.decode(l,{stream:!0});let x=d.indexOf(`
3
-
4
- `);for(;x!==-1;){let at=d.slice(0,x);d=d.slice(x+2);let B=ft(at);B&&(yield B),x=d.indexOf(`
5
-
6
- `)}}}finally{try{m.releaseLock()}catch{}}}function ft(e){if(!e.trim())return null;let t=null,r=[];for(let n of e.split(`
7
- `)){if(!n||n.startsWith(":"))continue;let o=n.indexOf(":");if(o===-1)continue;let s=n.slice(0,o),i=n.slice(o+1).replace(/^ /,"");s==="event"?t=i:s==="data"&&r.push(i)}return!t||r.length===0?null:{event:t,data:r.join(`
8
- `)}}async function*mt(e,t,r={}){let n=`/v1/projects/${encodeURIComponent(e)}/renders/${encodeURIComponent(t)}/stream`;for await(let o of dt(n,"iterRenderEvents",r)){let s=ut(o);s&&(yield s)}}function ut(e){let{event:t,data:r}=e;if(r===null||t!=="progress"&&t!=="complete"&&t!=="error")return null;let n;try{n=JSON.parse(r)}catch{return null}return{event:t,data:n}}var P={};y(P,{composeFromSuggestion:()=>bt,getComposeFromSuggestionUrl:()=>L,getListMediaSuggestionsUrl:()=>G,getResetMediaSuggestionsUrl:()=>F,getSuggestBriefsUrl:()=>$,listMediaSuggestions:()=>Pt,resetMediaSuggestions:()=>ht,suggestBriefs:()=>St});var L=e=>`/v1/projects/${e}/composition/from-suggestion`,bt=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(L(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},G=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}/suggestions?${n}`:`/v1/media/${e}/suggestions`},Pt=async(e,t,r)=>a(G(e,t),{...r,method:"GET"}),$=e=>`/v1/media/${e}/suggestions`,St=async(e,t)=>a($(e),{...t,method:"POST"}),F=e=>`/v1/media/${e}/suggestions`,ht=async(e,t)=>a(F(e),{...t,method:"DELETE"});var Z={};y(Z,{createComponent:()=>Tt,getBlankComponentSource:()=>qt,getComponent:()=>jt,getComponentSource:()=>At,getCreateComponentUrl:()=>V,getGetBlankComponentSourceUrl:()=>J,getGetComponentSourceUrl:()=>Y,getGetComponentUrl:()=>X,getListCatalogUrl:()=>D,getPatchComponentUrl:()=>z,getRepinComponentUrl:()=>_,getResolveBuiltinComponentUrl:()=>H,getUpdateComponentUrl:()=>W,listCatalog:()=>kt,patchComponent:()=>It,repinComponent:()=>vt,resolveBuiltinComponent:()=>Et,updateComponent:()=>Ot});var _=e=>`/v1/projects/${e}/components/native-upgrade`,vt=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(_(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},J=()=>"/v1/components/blank-source",qt=async e=>a(J(),{...e,method:"GET"}),H=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/components/builtin/resolve?${r}`:"/v1/components/builtin/resolve"},Et=async(e,t)=>a(H(e),{...t,method:"GET"}),D=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/components?${r}`:"/v1/components"},kt=async(e,t)=>a(D(e),{...t,method:"GET"}),V=()=>"/v1/components",Tt=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(V(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},W=e=>`/v1/components/${e}`,Ot=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(W(e),{...r,method:"PUT",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},z=e=>`/v1/components/${e}`,It=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(z(e),{...r,method:"PATCH",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},X=e=>`/v1/components/${e}`,jt=async(e,t)=>a(X(e),{...t,method:"GET"}),Y=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/components/${e}/source?${n}`:`/v1/components/${e}/source`},At=async(e,t,r)=>a(Y(e,t),{...r,method:"GET"});var oe={};y(oe,{cancelExport:()=>_t,createFcpxmlExport:()=>Gt,createPremiereExport:()=>$t,getCancelExportUrl:()=>re,getCreateFcpxmlExportUrl:()=>Q,getCreatePremiereExportUrl:()=>ee,getExport:()=>Ft,getGetExportUrl:()=>te});var Q=e=>`/v1/projects/${e}/exports/fcpxml`,Gt=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Q(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},ee=e=>`/v1/projects/${e}/exports/premiere`,$t=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(ee(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},te=(e,t)=>`/v1/projects/${e}/exports/${t}`,Ft=async(e,t,r)=>a(te(e,t),{...r,method:"GET"}),re=(e,t)=>`/v1/projects/${e}/exports/${t}/cancel`,_t=async(e,t,r)=>a(re(e,t),{...r,method:"POST"});var Ee={};y(Ee,{analyzeTimeline:()=>lr,analyzeTranscript:()=>ur,cancelHostedProcessingRun:()=>Yt,createMediaUpload:()=>Qt,createUploadToken:()=>Zt,deleteMedia:()=>nr,finalizeMedia:()=>tr,generateMedia:()=>rr,getAnalyzeTimelineUrl:()=>qe,getAnalyzeTranscriptUrl:()=>ve,getCancelHostedProcessingRunUrl:()=>pe,getCreateMediaUploadUrl:()=>de,getCreateUploadTokenUrl:()=>ce,getDeleteMediaUrl:()=>ge,getFinalizeMediaUrl:()=>me,getGenerateMediaUrl:()=>ue,getGetHostedProcessingArtifactUrl:()=>ae,getGetHostedProcessingRunUrl:()=>ie,getGetMediaContextUrl:()=>Ce,getGetMediaDownloadUrlUrl:()=>xe,getGetMediaTranscriptUrl:()=>Re,getGetMediaUrl:()=>ye,getHostedProcessingArtifact:()=>Xt,getHostedProcessingRun:()=>zt,getImportMediaUrl:()=>le,getListMediaFactsUrl:()=>Se,getListMediaUrl:()=>fe,getMedia:()=>sr,getMediaContext:()=>pr,getMediaDownloadUrl:()=>ir,getMediaTranscript:()=>ar,getPurchaseMediaFactUrl:()=>he,getSearchLibraryUrl:()=>ne,getStartHostedProcessingRunUrl:()=>se,getTriggerMatteBakeUrl:()=>Pe,getTriggerSubjectDetectionUrl:()=>be,importMedia:()=>or,listMedia:()=>er,listMediaFacts:()=>fr,purchaseMediaFact:()=>mr,searchLibrary:()=>Vt,startHostedProcessingRun:()=>Wt,triggerMatteBake:()=>dr,triggerSubjectDetection:()=>cr});var ne=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{let s=["mediaId"];if(Array.isArray(o)&&s.includes(n)){o.forEach(i=>{t.append(n,i===null?"null":String(i))});return}o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/media/search?${r}`:"/v1/media/search"},Vt=async(e,t)=>a(ne(e),{...t,method:"GET"}),se=e=>`/v1/media/${e}/processing-runs`,Wt=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(se(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},ie=(e,t)=>`/v1/media/${e}/processing-runs/${t}`,zt=async(e,t,r)=>a(ie(e,t),{...r,method:"GET"}),ae=(e,t,r)=>`/v1/media/${e}/processing-runs/${t}/artifacts/${r}`,Xt=async(e,t,r,n)=>a(ae(e,t,r),{...n,method:"GET"}),pe=(e,t)=>`/v1/media/${e}/processing-runs/${t}/cancel`,Yt=async(e,t,r)=>a(pe(e,t),{...r,method:"POST"}),ce=()=>"/v1/uploads/token",Zt=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(ce(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},de=()=>"/v1/media",Qt=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(de(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},fe=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/media?${r}`:"/v1/media"},er=async(e,t)=>a(fe(e),{...t,method:"GET"}),me=e=>`/v1/media/${e}/finalize`,tr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(me(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},ue=()=>"/v1/media/generate",rr=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(ue(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},le=()=>"/v1/media/import",or=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(le(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},ge=e=>`/v1/media/${e}`,nr=async(e,t)=>a(ge(e),{...t,method:"DELETE"}),ye=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}?${n}`:`/v1/media/${e}`},sr=async(e,t,r)=>a(ye(e,t),{...r,method:"GET"}),xe=e=>`/v1/media/${e}/download-url`,ir=async(e,t)=>a(xe(e),{...t,method:"GET"}),Re=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}/transcript?${n}`:`/v1/media/${e}/transcript`},ar=async(e,t,r)=>a(Re(e,t),{...r,method:"GET"}),Ce=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}/context?${n}`:`/v1/media/${e}/context`},pr=async(e,t,r)=>a(Ce(e,t),{...r,method:"GET"}),be=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}/detect-subjects?${n}`:`/v1/media/${e}/detect-subjects`},cr=async(e,t,r)=>a(be(e,t),{...r,method:"POST"}),Pe=e=>`/v1/media/${e}/matte`,dr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Pe(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Se=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/media/${e}/facts?${n}`:`/v1/media/${e}/facts`},fr=async(e,t,r)=>a(Se(e,t),{...r,method:"GET"}),he=e=>`/v1/media/${e}/facts`,mr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(he(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},ve=e=>`/v1/media/${e}/transcript/analyze`,ur=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(ve(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},qe=()=>"/v1/timeline-analysis",lr=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(qe(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})};var we={};y(we,{createProject:()=>yr,deleteProject:()=>Cr,getCreateProjectUrl:()=>Te,getDeleteProjectUrl:()=>je,getGetProjectContextUrl:()=>Ae,getGetProjectUrl:()=>Oe,getListProjectsUrl:()=>ke,getPatchProjectUrl:()=>Ie,getProject:()=>xr,getProjectContext:()=>br,listProjects:()=>gr,patchProject:()=>Rr});var ke=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/projects?${r}`:"/v1/projects"},gr=async(e,t)=>a(ke(e),{...t,method:"GET"}),Te=()=>"/v1/projects",yr=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(Te(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},Oe=e=>`/v1/projects/${e}`,xr=async(e,t)=>a(Oe(e),{...t,method:"GET"}),Ie=e=>`/v1/projects/${e}`,Rr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Ie(e),{...r,method:"PATCH",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},je=e=>`/v1/projects/${e}`,Cr=async(e,t)=>a(je(e),{...t,method:"DELETE"}),Ae=e=>`/v1/projects/${e}/context`,br=async(e,t)=>a(Ae(e),{...t,method:"GET"});var Fe={};y(Fe,{cancelRender:()=>qr,createRender:()=>Pr,getCancelRenderUrl:()=>Ne,getCreateRenderUrl:()=>Me,getGetRenderUrl:()=>Be,getListProjectRendersUrl:()=>Ue,getPreviewClipUrl:()=>Ke,getRefreshRenderUrlUrl:()=>Ge,getRender:()=>vr,getRetryRenderUrl:()=>Le,getStreamRenderUrl:()=>$e,listProjectRenders:()=>Sr,previewClip:()=>hr,refreshRenderUrl:()=>kr,retryRender:()=>Er,streamRender:()=>Tr});var Me=e=>`/v1/projects/${e}/renders`,Pr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Me(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Ue=(e,t)=>{let r=new URLSearchParams;Object.entries(t||{}).forEach(([o,s])=>{s!==void 0&&r.append(o,s===null?"null":String(s))});let n=r.toString();return n.length>0?`/v1/projects/${e}/renders?${n}`:`/v1/projects/${e}/renders`},Sr=async(e,t,r)=>a(Ue(e,t),{...r,method:"GET"}),Ke=e=>`/v1/projects/${e}/preview-clip`,hr=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Ke(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Be=(e,t)=>`/v1/projects/${e}/renders/${t}`,vr=async(e,t,r)=>a(Be(e,t),{...r,method:"GET"}),Ne=(e,t)=>`/v1/projects/${e}/renders/${t}/cancel`,qr=async(e,t,r)=>a(Ne(e,t),{...r,method:"POST"}),Le=(e,t)=>`/v1/projects/${e}/renders/${t}/retry`,Er=async(e,t,r)=>a(Le(e,t),{...r,method:"POST"}),Ge=(e,t)=>`/v1/projects/${e}/renders/${t}/refresh-url`,kr=async(e,t,r)=>a(Ge(e,t),{...r,method:"POST"}),$e=(e,t)=>`/v1/projects/${e}/renders/${t}/stream`,Tr=async(e,t,r)=>a($e(e,t),{...r,method:"GET"});var Xe={};y(Xe,{cancelMuxJob:()=>Br,createSession:()=>Ar,deleteSession:()=>Mr,getCancelMuxJobUrl:()=>ze,getCreateSessionUrl:()=>Je,getDeleteSessionUrl:()=>De,getGetMuxJobUrl:()=>We,getGetSessionUrl:()=>He,getListSessionsUrl:()=>_e,getMuxJob:()=>Kr,getSession:()=>wr,getTriggerMuxJobUrl:()=>Ve,listSessions:()=>jr,triggerMuxJob:()=>Ur});var _e=e=>{let t=new URLSearchParams;Object.entries(e||{}).forEach(([n,o])=>{o!==void 0&&t.append(n,o===null?"null":String(o))});let r=t.toString();return r.length>0?`/v1/sessions?${r}`:"/v1/sessions"},jr=async(e,t)=>a(_e(e),{...t,method:"GET"}),Je=()=>"/v1/sessions",Ar=async(e,t)=>{let r=n=>{if(!n)return{};if(n instanceof Headers)return Object.fromEntries(n.entries());if(Symbol.iterator in n)return Object.fromEntries(Array.from(n,s=>Array.from(s)));let o={};for(let[s,i]of Object.entries(n))i!==void 0&&(o[s]=i);return o};return a(Je(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},He=e=>`/v1/sessions/${e}`,wr=async(e,t)=>a(He(e),{...t,method:"GET"}),De=e=>`/v1/sessions/${e}`,Mr=async(e,t)=>a(De(e),{...t,method:"DELETE"}),Ve=e=>`/v1/sessions/${e}/mux-job`,Ur=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(Ve(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},We=e=>`/v1/sessions/${e}/mux-job`,Kr=async(e,t)=>a(We(e),{...t,method:"GET"}),ze=e=>`/v1/sessions/${e}/mux-job/cancel`,Br=async(e,t,r)=>{let n=o=>{if(!o)return{};if(o instanceof Headers)return Object.fromEntries(o.entries());if(Symbol.iterator in o)return Object.fromEntries(Array.from(o,i=>Array.from(i)));let s={};for(let[i,p]of Object.entries(o))p!==void 0&&(s[i]=p);return s};return a(ze(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})};var _r=[3,4],Jr={version:4,componentId:"blank-component",template:`<template><div id="root" data-composition-id="blank-component" data-width="1920" data-height="1080" data-no-timeline data-composition-variables='[{"id":"background","type":"color","label":"Background","default":"#101014"}]'><div data-cf-scene></div></div><script>
9
- const { h, MediaTileScene } = __cfScene;
10
- function Blank({ params }) {
11
- return h(MediaTileScene, { streams: {}, tiles: [], background: params.background ?? '#101014' });
12
- }
13
- __cfScene.mount({ root: document.getElementById('root'), component: Blank, variables: __hyperframes.getVariables() });
14
- </script></template>`,manifest:{version:4,runtime:"hyperframes",hfContract:1,kind:"scene",assets:{},graphics:{api:"webgl2",required:!0,accelerationPreference:"software-allowed"},alphaPolicy:"allows-opaque"},definition:{inputSchema:{type:"object",additionalProperties:!1,properties:{background:{type:"string",pattern:"^#[0-9a-fA-F]{6}$",default:"#101014",title:"Background"}}},defaults:{},brandBindings:[],timing:{defaultDuration:{frames:90,fps:30}},capabilities:[{kind:"clip"}]}};var E="X-CueFrame-Client";var Hr=/^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$/,Dr=["web","console","clips"];function Vr(e,t){return Dr.includes(e)===(t==="browser")}function Ye(e){if(!Hr.test(e.version))throw new Error(`${E} cannot carry the version ${JSON.stringify(e.version)}.`);if(!Vr(e.surface,e.os))throw new Error(`${E} cannot carry ${e.surface} on ${e.os}.`);return`${e.surface}/${e.version}/${e.os}`}function Ze(e){return e==="darwin"?"macos":e==="win32"?"windows":e==="linux"?"linux":"unknown"}import{readFileSync as Wr,writeFileSync as zr,mkdirSync as Xr,existsSync as Yr}from"fs";import{join as Qe}from"path";import{homedir as Zr}from"os";var f={Success:0,UserError:2,ApiClientError:3,ApiServerError:4,NetworkError:5,PaymentRequired:6};function A(e){if(e instanceof u){if(e.status===402)return f.PaymentRequired;if(e.status>=500)return f.ApiServerError;if(e.status>=400)return f.ApiClientError}let t=e?.exitCode;return typeof t=="number"?t:f.NetworkError}function _h(e){return e===402?f.PaymentRequired:e>=500?f.ApiServerError:e>=400?f.ApiClientError:f.Success}function S(e){process.exit(e)}var et=Qe(Zr(),".cueframe"),k=Qe(et,"auth.json"),R={local:"http://127.0.0.1:3211",prod:"https://api.cueframe.ai"},Qr="prod";function zh(e=Qr){return process.env.CUEFRAME_API_URL??R[e]??R.prod}var h=class extends Error{constructor(r,n){super(n);this.code=r;this.name="AuthStoreError"}code;exitCode=f.UserError};function Xh(e){if(!/^cf_(?:live|test)_[A-Za-z0-9_-]{8,}$/.test(e))throw new h("auth_invalid","Invalid API key. Expected a key beginning with cf_live_ or cf_test_.")}function tt(){if(!Yr(k))return{targets:{}};let e=Wr(k,"utf-8");try{return JSON.parse(e)}catch{throw new h("auth_config_corrupt",`${k} is corrupt and cannot be parsed. Delete it and re-run \`cueframe login\`.`)}}function eo(e){Xr(et,{recursive:!0,mode:448}),zr(k,JSON.stringify(e,null,2),{mode:384})}function Yh(e,t="prod",r){let n=tt(),o=R[t]??R.prod;n.targets[t]={apiKey:e,apiUrl:r??o},eo(n)}function rt(e="prod"){let t=process.env.CUEFRAME_API_KEY,r=process.env.CUEFRAME_API_URL;if(t)return{apiKey:t,apiUrl:r??R[e]??R.prod};let o=tt().targets[e];if(!o)throw new h("auth_missing",`No auth configured for target "${e}". Run \`cueframe login --target ${e}\` (browser sign-in) or \`cueframe auth <api-key> --target ${e}\` (CI / headless).`);return o}function to(){return{[E]:Ye({surface:"cli",version:"0.9.4",os:Ze(process.platform)})}}function ot(e){let{apiKey:t,apiUrl:r}=rt(e);O({baseUrl:r,apiKey:t,headers:to()})}function T(e){let t=e instanceof u?`${e.message} (${e.code}${e.status?`, ${e.status}`:""})`:e instanceof Error?e.message:String(e),r=j(e);return r?`${t}
15
- \u2192 ${r}`:t}import ro from"ora";import oo from"pino";var no="v1",nt=oo({level:"trace",base:{schemaVersion:no},messageKey:"event",timestamp:()=>`,"ts":${Date.now()}`,formatters:{level:()=>({_:0})}});function w(e,t){return ro({text:e,isSilent:!!t}).start()}function C(e,t,r={}){e.json&&nt.info(r,t)}function iv(e,t,r){if(e.json){console.log(JSON.stringify(t,null,2));return}r()}function M(e,t,r,n){let o=r instanceof Error?r.message:String(r),s=typeof r?.code=="string"?r.code:void 0,i=r?.status;e.json?nt.info({phase:t,message:o,...s?{code:s}:{},...typeof i=="number"?{status:i}:{},exitCode:n},"error"):process.stderr.write(`\u2716 ${t}: ${T(r)}
16
- `)}function U(e,t,r,n){e.json&&M(e,t,r,n)}function av(e,t){t.json||console.log(e)}function so(e){for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);if(r<=31||r===127)return!0}return!1}function it(e,t,r){e.length===0&&st(`${t} is empty.`,r),so(e)&&st(`${t} contains a control character (newline, tab, or null byte). Identifiers must be plain text \u2014 check for a stray copy-paste artifact.`,r)}function st(e,t){M(t,"preflight",new Error(e),f.UserError),S(f.UserError)}var io=5e3,K=300*1e3;async function xv(e,t){if(it(e,"mediaItemId",t),t.dryRun){C(t,"analyze_dry_run",{mediaItemId:e,target:t.target,wait:!!t.wait,wouldCall:"POST /v1/media/:id/suggestions"}),t.json||console.log(`[dry-run] Would trigger clip analysis for ${e} on ${t.target}.`);return}ot(t.target),C(t,"analyze_prepare",{mediaItemId:e,target:t.target,wait:!!t.wait});let r=w("Triggering clip analysis\u2026",t.json),n;try{n=await P.suggestBriefs(e),r.succeed(`Analysis ${n.alreadyRunning?"already running":"started"}`)}catch(i){r.fail(`Failed to start analysis: ${T(i)}`),U(t,"analyze_prepare",i,A(i)),S(A(i))}if(C(t,"analyze_ready",{mediaItemId:e,status:n.status,alreadyRunning:!!n.alreadyRunning}),!t.wait){t.json||console.log(`
17
- Run \`cueframe clips ${e}\` to check results.`);return}let o=w("Waiting for analysis to complete\u2026",t.json),s=Date.now();for(;;){await new Promise(i=>setTimeout(i,io)),Date.now()-s>K&&(o.fail(`Timed out after ${Math.round(K/1e3)}s. Run \`cueframe clips ${e}\` to check later.`),U(t,"analyze_progress",new Error(`Analysis did not complete within ${Math.round(K/1e3)}s`),f.UserError),S(f.UserError));try{let i=await P.listMediaSuggestions(e);if(i.suggestions.length>0){o.succeed(`Analysis complete \u2014 ${i.suggestions.length} clips found`),C(t,"analyze_complete",{mediaItemId:e,durationMs:Date.now()-s,suggestionCount:i.suggestions.length,suggestions:i.suggestions}),t.json||i.suggestions.forEach((m,c)=>{let d=(m.trim.end-m.trim.start).toFixed(1);console.log(`
18
- ${c+1}. ${m.title} (${m.id})`),console.log(` ${m.trim.start.toFixed(1)}s \u2013 ${m.trim.end.toFixed(1)}s (${d}s) score: ${m.score}`),console.log(` ${m.reason}`)});return}let p=Math.round((Date.now()-s)/1e3);o.text=`Waiting for analysis\u2026 (${p}s)`,C(t,"analyze_progress",{mediaItemId:e,elapsedSec:p})}catch{}}}export{u as a,O as b,N as c,a as d,j as e,mt as f,P as g,Z as h,oe as i,Ee as j,we as k,Fe as l,Xe as m,_r as n,Jr as o,f as p,A as q,_h as r,S as s,zh as t,Xh as u,Yh as v,to as w,ot as x,T as y,w as z,C as A,iv as B,M as C,U as D,av as E,it as F,xv as G};