cueframe 0.8.1 → 0.8.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.
package/README.md CHANGED
@@ -1,77 +1,76 @@
1
1
  # cueframe
2
2
 
3
3
  Agent-native CLI for **CueFrame** — turn media into rendered video from the
4
- terminal. Every command speaks `--json` (an NDJSON event stream) and the binary
5
- self-describes via `npx -y cueframe describe --json`, so agents can drive it without
4
+ terminal. Commands support `--json` for structured output and the binary
5
+ self-describes via `npx -y cueframe@0.8 describe --json`, so agents can drive it without
6
6
  guesswork.
7
7
 
8
8
  > Connects to the hosted CueFrame service — create an API key at
9
- > [app.cueframe.ai](https://app.cueframe.ai), or use `npx -y cueframe login`.
9
+ > [app.cueframe.ai](https://app.cueframe.ai), or use `npx -y cueframe@0.8 login`.
10
10
 
11
11
  ## Run it
12
12
 
13
- There is nothing to install. Every command in this README runs as
14
- `npx -y cueframe …` and is executable verbatim:
13
+ Run the CLI without a global installation:
15
14
 
16
15
  ```bash
17
- npx -y cueframe --help
16
+ npx -y cueframe@0.8 --help
18
17
  ```
19
18
 
20
- `npx -y cueframe install` wires the CueFrame MCP server into every agent on your
21
- machine — but note it installs **no binary**: npx unpacks to an ephemeral cache and
22
- leaves nothing on your `PATH`. That is deliberate. `npx` re-resolves the current
23
- version on every call (~0.5s warm), so these commands can never go stale the way a
24
- pinned global install does.
19
+ Requires **Node.js 24 or newer**. The `@0.8` selector keeps these commands on the documented minor release. `npx` downloads the package into its cache; it does not install a persistent binary on your `PATH`.
25
20
 
26
- Running many commands in a row and want to skip that overhead? Install it once and
27
- drop the `npx -y ` prefix:
21
+ For repeated terminal use, you can install that release globally:
28
22
 
29
23
  ```bash
30
- npm i -g cueframe # optional — needs a user-writable npm prefix
24
+ npm install -g cueframe@0.8
31
25
  ```
32
26
 
33
- This is an optimization, not the supported path. On a default Linux install it fails
34
- with `EACCES: permission denied, mkdir '/usr/local/lib/node_modules/cueframe'` unless
35
- you have configured an npm prefix in your home directory.
27
+ The same commands then run as `cueframe …`.
36
28
 
37
29
  ## Authenticate
38
30
 
39
31
  ```bash
40
- npx -y cueframe auth <cf_live_… key> # static API key (CI / headless)
32
+ npx -y cueframe@0.8 auth <cf_live_… key> # static API key (CI / headless)
41
33
  # or
42
- npx -y cueframe login # OAuth device flow (browser)
34
+ npx -y cueframe@0.8 login # OAuth device flow (browser)
43
35
  ```
44
36
 
45
37
  The key can also be supplied via the `CUEFRAME_API_KEY` environment variable.
46
38
 
39
+ ## Check your connection
40
+
41
+ ```bash
42
+ npx -y cueframe@0.8 api GET /v1/me --json
43
+ ```
44
+
45
+ This reads your account and credit entitlements without rendering. Cloud processing and rendering consume credits; see [cloud rates](https://cueframe.ai/pricing).
46
+
47
47
  ## Quick start — upload → author → render
48
48
 
49
49
  ```bash
50
50
  # 1. Register media (video / image / audio)
51
- npx -y cueframe upload ./source.mp4 --json # → mediaItemId
51
+ npx -y cueframe@0.8 upload ./source.mp4 --json # → mediaItemId
52
52
 
53
53
  # 2. Create a project (sets aspect / format)
54
- npx -y cueframe project create -n promo -a 9:16 --json # → projectId
54
+ npx -y cueframe@0.8 project create -n promo -a 9:16 --json # → projectId
55
55
 
56
56
  # 3. Author the composition — tracks of clips, per-clip reframe/trim,
57
57
  # optional captions. The composition is the source of truth.
58
- npx -y cueframe composition put <projectId> -b @composition.json
58
+ npx -y cueframe@0.8 composition put <projectId> -b @composition.json
59
59
 
60
60
  # 4. Render the saved composition to MP4 (queues, SSE-watches, downloads)
61
- npx -y cueframe render <projectId> -o out.mp4 --json
61
+ npx -y cueframe@0.8 render <projectId> -o out.mp4 --json
62
62
  ```
63
63
 
64
64
  `render` takes only a project id and renders whatever composition is saved on
65
- it — no clip suggestion required. Run `npx -y cueframe describe --json` for the full
66
- composition schema and every command + flag.
65
+ it — no clip suggestion required. Run `npx -y cueframe@0.8 describe --json` for command arguments and options. See the [API reference](https://docs.cueframe.ai/docs/api) for composition fields.
67
66
 
68
67
  ## Let CueFrame pick the clip (podcast → short)
69
68
 
70
69
  ```bash
71
- npx -y cueframe upload ./long.mp4 --analyze --json # media + AI clip suggestions
72
- npx -y cueframe clips <mediaItemId> --json # list suggestions (sug_…)
73
- npx -y cueframe project create -n short -a 9:16 --from-suggestion <sug_…> --json
74
- npx -y cueframe render <projectId> -o short.mp4 --json
70
+ npx -y cueframe@0.8 upload ./long.mp4 --analyze --json # media + AI clip suggestions
71
+ npx -y cueframe@0.8 clips <mediaItemId> --json # list suggestions (sug_…)
72
+ npx -y cueframe@0.8 project create -n short -a 9:16 --from-suggestion <sug_…> --json
73
+ npx -y cueframe@0.8 render <projectId> -o short.mp4 --json
75
74
  ```
76
75
 
77
76
  Both paths converge on `render`; the suggestion on-ramp just authors the
@@ -85,10 +84,10 @@ The public catalog lives in `cueframe-ai/cueframe-templates`; your org keeps
85
84
  its own under `POST /v1/templates`.
86
85
 
87
86
  ```bash
88
- cueframe template run yosemite-warp-text --preset granite --media source=sample --values text=CARVED -o carved.mp4
89
- cueframe template run ./template.cueframe --media source=./clip.mp4 --values title="Journey" --no-render --json
90
- cueframe template status <jobId> --wait --json # reconnect to a running preparation
91
- cueframe template validate ./template.cueframe # on the API with your key; nothing is stored
87
+ npx -y cueframe@0.8 template run yosemite-warp-text --preset granite --media source=sample --values text=CARVED -o carved.mp4
88
+ npx -y cueframe@0.8 template run ./template.cueframe --media source=./clip.mp4 --values title="Journey" --no-render --json
89
+ npx -y cueframe@0.8 template status <jobId> --wait --json # reconnect to a running preparation
90
+ npx -y cueframe@0.8 template validate ./template.cueframe # on the API with your key; nothing is stored
92
91
  ```
93
92
 
94
93
  `run` publishes a local document to your org (a catalog slug is imported on
@@ -114,36 +113,45 @@ prepared matte at another bake version.
114
113
  ## Wire it into your agents
115
114
 
116
115
  ```bash
117
- npx -y cueframe install
116
+ npx -y cueframe@0.8 install
118
117
  ```
119
118
 
120
- Detects every agent on the machine — Claude Code, Cursor, Codex, VS Code, Windsurf,
121
- Zed, Antigravity CLI, Copilot CLI and more — and wires the CueFrame MCP server into each
122
- one's config. Auth happens on the agent's first call via a browser "Allow"; no API key.
119
+ Detects supported local agents and adds `https://api.cueframe.ai/v1/mcp` to their configuration. It also copies the bundled skills to `~/.agents/skills` and `~/.claude/skills`, preserving locally changed skills by default. This can update multiple detected clients; inspect the changes first:
123
120
 
124
- It also copies the usage skills to `~/.claude/skills/`. **Only Claude Code reads that
125
- directory** — every other agent gets the same verb surface as MCP tools from the server,
126
- so there is nothing further to install for them.
121
+ ```bash
122
+ npx -y cueframe@0.8 install --dry-run --json
123
+ ```
127
124
 
128
- Claude Desktop and ChatGPT can't be wired from the command line (neither reads a local
129
- MCP config) — add `https://api.cueframe.ai/v1/mcp` as a custom connector instead.
125
+ Restart your agent session after installation. Interactive MCP clients open a browser to authorize on the first call. ChatGPT uses its hosted connector setup separately; see the [connection guide](https://docs.cueframe.ai/docs/setup).
130
126
 
131
127
  ## For agents
132
128
 
133
- - **`--json` everywhere** — NDJSON lifecycle: `<verb>_prepare → <verb>_progress* → <verb>_complete | error`, plus a non-zero exit on failure.
134
- - **`npx -y cueframe describe --json`** — the full command tree as structured JSON.
135
- - **`npx -y cueframe api <METHOD> <path>`** — raw escape hatch over the v1 API.
129
+ - **`--json`** — lifecycle events use NDJSON: `<verb>_prepare → <verb>_progress* → <verb>_complete | error`, plus a non-zero exit on failure.
130
+ - **`npx -y cueframe@0.8 describe --json`** — the full command tree as structured JSON.
131
+ - **`npx -y cueframe@0.8 api <METHOD> <path>`** — raw escape hatch over the v1 API.
136
132
 
137
133
  ## Common commands
138
134
 
139
135
  | Need to… | Command |
140
136
  |---|---|
141
- | List projects | `npx -y cueframe list` |
142
- | Read a composition + ETag | `npx -y cueframe composition get <projectId> --json` |
143
- | Write a composition | `npx -y cueframe composition put <projectId> -b @comp.json` |
144
- | Export to Final Cut / Premiere | `npx -y cueframe export fcpxml \| premiere <projectId> -s <sug_…> --wait -o cut.zip` |
145
- | Validate without mutating | append `--dry-run` |
137
+ | List projects | `npx -y cueframe@0.8 list` |
138
+ | Read a composition + ETag | `npx -y cueframe@0.8 composition get <projectId> --json` |
139
+ | Write a composition | `npx -y cueframe@0.8 composition put <projectId> -b @comp.json` |
140
+ | Export to Final Cut / Premiere | `npx -y cueframe@0.8 export fcpxml \| premiere <projectId> -s <sug_…> --wait -o cut.zip` |
141
+ | Validate without mutating | use `--dry-run` where command help lists it |
142
+
143
+ ## Render existing projects from a script
144
+
145
+ After authentication, render each saved project in sequence. This uses the existing composition and downloads the MP4; it does not create an edit. Each render is metered.
146
+
147
+ ```bash
148
+ set -e
149
+ for project_id in "$@"; do
150
+ npx -y cueframe@0.8 render "$project_id" -o "${project_id}.mp4" --json
151
+ done
152
+ ```
146
153
 
154
+ Save this as `render-projects.sh` and pass project IDs: `bash render-projects.sh PROJECT_ID_1 PROJECT_ID_2`. `set -e` stops the batch on a failed command. Lifecycle output is NDJSON, so consume one JSON object per line. Check [the API quickstart](https://cueframe.ai/api.md) for retrieving an existing render job after an interrupted connection; do not submit a new render merely to check its status.
147
155
  ---
148
156
 
149
157
  © CueFrame, Inc. Open source under Apache-2.0.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{F as a}from"./chunk-C4HCB4HG.js";import"./chunk-3QSA3EBY.js";export{a as analyzeCommand};
@@ -0,0 +1,12 @@
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 I(e){return g={timeoutMs:3e4,...e},g}function j(){return g}function tt(e,t){return/^https?:\/\//.test(t)?t:e.replace(/\/$/,"")+(t.startsWith("/")?t:`/${t}`)}async function L(e,t={}){if(!g.baseUrl)throw new Error("@cueframe/sdk: createClient({baseUrl}) must be called before issuing requests.");let r=g.fetch??fetch,n=tt(g.baseUrl,e),o=new Headers({accept:"application/json"});for(let[c,f]of Object.entries(g.headers??{}))o.set(c,f);t.headers&&new Headers(t.headers).forEach((c,f)=>o.set(f,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),d=t.signal?AbortSignal.any([t.signal,i.signal]):i.signal;try{let c=await r(n,{...t,headers:o,signal:d}),f={};c.headers.forEach((b,x)=>{f[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:f,body:l,requestId:f["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 L(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 rt={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 O(e){return e instanceof u?rt[e.code]??null:null}async function*ot(e,t,r){let n=j();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 d=p.body.getReader(),c=new TextDecoder("utf-8"),f="";try{for(;;){let{value:l,done:b}=await d.read();if(b)break;f+=c.decode(l,{stream:!0});let x=f.indexOf(`
3
+
4
+ `);for(;x!==-1;){let et=f.slice(0,x);f=f.slice(x+2);let B=nt(et);B&&(yield B),x=f.indexOf(`
5
+
6
+ `)}}}finally{try{d.releaseLock()}catch{}}}function nt(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*st(e,t,r={}){let n=`/v1/projects/${encodeURIComponent(e)}/renders/${encodeURIComponent(t)}/stream`;for await(let o of ot(n,"iterRenderEvents",r)){let s=it(o);s&&(yield s)}}function it(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:()=>ut,getComposeFromSuggestionUrl:()=>N,getListMediaSuggestionsUrl:()=>G,getResetMediaSuggestionsUrl:()=>$,getSuggestBriefsUrl:()=>F,listMediaSuggestions:()=>lt,resetMediaSuggestions:()=>yt,suggestBriefs:()=>gt});var N=e=>`/v1/projects/${e}/composition/from-suggestion`,ut=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(N(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`},lt=async(e,t,r)=>a(G(e,t),{...r,method:"GET"}),F=e=>`/v1/media/${e}/suggestions`,gt=async(e,t)=>a(F(e),{...t,method:"POST"}),$=e=>`/v1/media/${e}/suggestions`,yt=async(e,t)=>a($(e),{...t,method:"DELETE"});var Y={};y(Y,{createComponent:()=>bt,getComponent:()=>ht,getComponentSource:()=>vt,getCreateComponentUrl:()=>D,getGetComponentSourceUrl:()=>X,getGetComponentUrl:()=>z,getListCatalogUrl:()=>H,getPatchComponentUrl:()=>V,getRepinComponentUrl:()=>J,getResolveBuiltinComponentUrl:()=>_,getUpdateComponentUrl:()=>W,listCatalog:()=>Ct,patchComponent:()=>St,repinComponent:()=>xt,resolveBuiltinComponent:()=>Rt,updateComponent:()=>Pt});var J=e=>`/v1/projects/${e}/components/native-upgrade`,xt=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(J(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},_=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"},Rt=async(e,t)=>a(_(e),{...t,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?${r}`:"/v1/components"},Ct=async(e,t)=>a(H(e),{...t,method:"GET"}),D=()=>"/v1/components",bt=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(D(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},W=e=>`/v1/components/${e}`,Pt=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)})},V=e=>`/v1/components/${e}`,St=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(V(e),{...r,method:"PATCH",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},z=e=>`/v1/components/${e}`,ht=async(e,t)=>a(z(e),{...t,method:"GET"}),X=(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`},vt=async(e,t,r)=>a(X(e,t),{...r,method:"GET"});var re={};y(re,{cancelExport:()=>Mt,createFcpxmlExport:()=>Ot,createPremiereExport:()=>wt,getCancelExportUrl:()=>te,getCreateFcpxmlExportUrl:()=>Z,getCreatePremiereExportUrl:()=>Q,getExport:()=>At,getGetExportUrl:()=>ee});var Z=e=>`/v1/projects/${e}/exports/fcpxml`,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(Z(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Q=e=>`/v1/projects/${e}/exports/premiere`,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(Q(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},ee=(e,t)=>`/v1/projects/${e}/exports/${t}`,At=async(e,t,r)=>a(ee(e,t),{...r,method:"GET"}),te=(e,t)=>`/v1/projects/${e}/exports/${t}/cancel`,Mt=async(e,t,r)=>a(te(e,t),{...r,method:"POST"});var be={};y(be,{analyzeTimeline:()=>er,analyzeTranscript:()=>Qt,createMediaUpload:()=>Gt,createUploadToken:()=>Nt,deleteMedia:()=>Ht,finalizeMedia:()=>$t,generateMedia:()=>Jt,getAnalyzeTimelineUrl:()=>Ce,getAnalyzeTranscriptUrl:()=>Re,getCreateMediaUploadUrl:()=>se,getCreateUploadTokenUrl:()=>ne,getDeleteMediaUrl:()=>fe,getFinalizeMediaUrl:()=>ae,getGenerateMediaUrl:()=>pe,getGetMediaContextUrl:()=>ue,getGetMediaTranscriptUrl:()=>de,getGetMediaUrl:()=>me,getImportMediaUrl:()=>ce,getListMediaFactsUrl:()=>ye,getListMediaUrl:()=>ie,getMedia:()=>Dt,getMediaContext:()=>Vt,getMediaTranscript:()=>Wt,getPurchaseMediaFactUrl:()=>xe,getSearchLibraryUrl:()=>oe,getTriggerMatteBakeUrl:()=>ge,getTriggerSubjectDetectionUrl:()=>le,importMedia:()=>_t,listMedia:()=>Ft,listMediaFacts:()=>Yt,purchaseMediaFact:()=>Zt,searchLibrary:()=>Lt,triggerMatteBake:()=>Xt,triggerSubjectDetection:()=>zt});var oe=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/search?${r}`:"/v1/media/search"},Lt=async(e,t)=>a(oe(e),{...t,method:"GET"}),ne=()=>"/v1/uploads/token",Nt=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(ne(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},se=()=>"/v1/media",Gt=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(se(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},ie=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"},Ft=async(e,t)=>a(ie(e),{...t,method:"GET"}),ae=e=>`/v1/media/${e}/finalize`,$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(ae(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},pe=()=>"/v1/media/generate",Jt=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(pe(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},ce=()=>"/v1/media/import",_t=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)})},fe=e=>`/v1/media/${e}`,Ht=async(e,t)=>a(fe(e),{...t,method:"DELETE"}),me=e=>`/v1/media/${e}`,Dt=async(e,t)=>a(me(e),{...t,method:"GET"}),de=(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`},Wt=async(e,t,r)=>a(de(e,t),{...r,method:"GET"}),ue=e=>`/v1/media/${e}/context`,Vt=async(e,t)=>a(ue(e),{...t,method:"GET"}),le=(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`},zt=async(e,t,r)=>a(le(e,t),{...r,method:"POST"}),ge=e=>`/v1/media/${e}/matte`,Xt=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(ge(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},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}/facts?${n}`:`/v1/media/${e}/facts`},Yt=async(e,t,r)=>a(ye(e,t),{...r,method:"GET"}),xe=e=>`/v1/media/${e}/facts`,Zt=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(xe(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Re=e=>`/v1/media/${e}/transcript/analyze`,Qt=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(Re(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Ce=()=>"/v1/timeline-analysis",er=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)})};var Ee={};y(Ee,{createProject:()=>rr,deleteProject:()=>sr,getCreateProjectUrl:()=>Se,getDeleteProjectUrl:()=>qe,getGetProjectContextUrl:()=>ke,getGetProjectUrl:()=>he,getListProjectsUrl:()=>Pe,getPatchProjectUrl:()=>ve,getProject:()=>or,getProjectContext:()=>ir,listProjects:()=>tr,patchProject:()=>nr});var Pe=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"},tr=async(e,t)=>a(Pe(e),{...t,method:"GET"}),Se=()=>"/v1/projects",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(Se(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},he=e=>`/v1/projects/${e}`,or=async(e,t)=>a(he(e),{...t,method:"GET"}),ve=e=>`/v1/projects/${e}`,nr=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:"PATCH",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},qe=e=>`/v1/projects/${e}`,sr=async(e,t)=>a(qe(e),{...t,method:"DELETE"}),ke=e=>`/v1/projects/${e}/context`,ir=async(e,t)=>a(ke(e),{...t,method:"GET"});var Ke={};y(Ke,{cancelRender:()=>mr,createRender:()=>ar,getCancelRenderUrl:()=>we,getCreateRenderUrl:()=>Te,getGetRenderUrl:()=>Oe,getListProjectRendersUrl:()=>Ie,getPreviewClipUrl:()=>je,getRefreshRenderUrlUrl:()=>Me,getRender:()=>fr,getRetryRenderUrl:()=>Ae,getStreamRenderUrl:()=>Ue,listProjectRenders:()=>pr,previewClip:()=>cr,refreshRenderUrl:()=>ur,retryRender:()=>dr,streamRender:()=>lr});var Te=e=>`/v1/projects/${e}/renders`,ar=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(Te(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Ie=(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`},pr=async(e,t,r)=>a(Ie(e,t),{...r,method:"GET"}),je=e=>`/v1/projects/${e}/preview-clip`,cr=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(je(e),{...r,method:"POST",headers:{"Content-Type":"application/json",...n(r?.headers)},body:JSON.stringify(t)})},Oe=(e,t)=>`/v1/projects/${e}/renders/${t}`,fr=async(e,t,r)=>a(Oe(e,t),{...r,method:"GET"}),we=(e,t)=>`/v1/projects/${e}/renders/${t}/cancel`,mr=async(e,t,r)=>a(we(e,t),{...r,method:"POST"}),Ae=(e,t)=>`/v1/projects/${e}/renders/${t}/retry`,dr=async(e,t,r)=>a(Ae(e,t),{...r,method:"POST"}),Me=(e,t)=>`/v1/projects/${e}/renders/${t}/refresh-url`,ur=async(e,t,r)=>a(Me(e,t),{...r,method:"POST"}),Ue=(e,t)=>`/v1/projects/${e}/renders/${t}/stream`,lr=async(e,t,r)=>a(Ue(e,t),{...r,method:"GET"});var Je={};y(Je,{createSession:()=>Rr,deleteSession:()=>br,getCreateSessionUrl:()=>Le,getDeleteSessionUrl:()=>Ge,getGetMuxJobUrl:()=>$e,getGetSessionUrl:()=>Ne,getListSessionsUrl:()=>Be,getMuxJob:()=>Sr,getSession:()=>Cr,getTriggerMuxJobUrl:()=>Fe,listSessions:()=>xr,triggerMuxJob:()=>Pr});var Be=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"},xr=async(e,t)=>a(Be(e),{...t,method:"GET"}),Le=()=>"/v1/sessions",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(Le(),{...t,method:"POST",headers:{"Content-Type":"application/json",...r(t?.headers)},body:JSON.stringify(e)})},Ne=e=>`/v1/sessions/${e}`,Cr=async(e,t)=>a(Ne(e),{...t,method:"GET"}),Ge=e=>`/v1/sessions/${e}`,br=async(e,t)=>a(Ge(e),{...t,method:"DELETE"}),Fe=e=>`/v1/sessions/${e}/mux-job`,Pr=async(e,t)=>a(Fe(e),{...t,method:"POST"}),$e=e=>`/v1/sessions/${e}/mux-job`,Sr=async(e,t)=>a($e(e),{...t,method:"GET"});var Tr=[3,4];var k="X-CueFrame-Client";var Ir=/^[A-Za-z0-9][A-Za-z0-9._+-]{0,31}$/,jr=["web","console","clips"];function Or(e,t){return jr.includes(e)===(t==="browser")}function _e(e){if(!Ir.test(e.version))throw new Error(`${k} cannot carry the version ${JSON.stringify(e.version)}.`);if(!Or(e.surface,e.os))throw new Error(`${k} cannot carry ${e.surface} on ${e.os}.`);return`${e.surface}/${e.version}/${e.os}`}function He(e){return e==="darwin"?"macos":e==="win32"?"windows":e==="linux"?"linux":"unknown"}import{readFileSync as wr,writeFileSync as Ar,mkdirSync as Mr,existsSync as Ur}from"fs";import{join as De}from"path";import{homedir as Kr}from"os";var m={Success:0,UserError:2,ApiClientError:3,ApiServerError:4,NetworkError:5,PaymentRequired:6};function w(e){if(e instanceof u){if(e.status===402)return m.PaymentRequired;if(e.status>=500)return m.ApiServerError;if(e.status>=400)return m.ApiClientError}let t=e?.exitCode;return typeof t=="number"?t:m.NetworkError}function XP(e){return e===402?m.PaymentRequired:e>=500?m.ApiServerError:e>=400?m.ApiClientError:m.Success}function S(e){process.exit(e)}var We=De(Kr(),".cueframe"),E=De(We,"auth.json"),R={local:"http://127.0.0.1:3211",prod:"https://api.cueframe.ai"},Br="prod";function rS(e=Br){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=m.UserError};function oS(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 Ve(){if(!Ur(E))return{targets:{}};let e=wr(E,"utf-8");try{return JSON.parse(e)}catch{throw new h("auth_config_corrupt",`${E} is corrupt and cannot be parsed. Delete it and re-run \`cueframe login\`.`)}}function Lr(e){Mr(We,{recursive:!0,mode:448}),Ar(E,JSON.stringify(e,null,2),{mode:384})}function nS(e,t="prod",r){let n=Ve(),o=R[t]??R.prod;n.targets[t]={apiKey:e,apiUrl:r??o},Lr(n)}function ze(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=Ve().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 Nr(){return{[k]:_e({surface:"cli",version:"0.8.3",os:He(process.platform)})}}function Xe(e){let{apiKey:t,apiUrl:r}=ze(e);I({baseUrl:r,apiKey:t,headers:Nr()})}function T(e){let t=e instanceof u?`${e.message} (${e.code}${e.status?`, ${e.status}`:""})`:e instanceof Error?e.message:String(e),r=O(e);return r?`${t}
9
+ \u2192 ${r}`:t}import Gr from"ora";import Fr from"pino";var $r="v1",Ye=Fr({level:"trace",base:{schemaVersion:$r},messageKey:"event",timestamp:()=>`,"ts":${Date.now()}`,formatters:{level:()=>({_:0})}});function A(e,t){return Gr({text:e,isSilent:!!t}).start()}function C(e,t,r={}){e.json&&Ye.info(r,t)}function uS(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?Ye.info({phase:t,message:o,...s?{code:s}:{},...typeof i=="number"?{status:i}:{},exitCode:n},"error"):process.stderr.write(`\u2716 ${t}: ${T(r)}
10
+ `)}function U(e,t,r,n){e.json&&M(e,t,r,n)}function lS(e,t){t.json||console.log(e)}function Jr(e){for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);if(r<=31||r===127)return!0}return!1}function Qe(e,t,r){e.length===0&&Ze(`${t} is empty.`,r),Jr(e)&&Ze(`${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 Ze(e,t){M(t,"preflight",new Error(e),m.UserError),S(m.UserError)}var _r=5e3,K=300*1e3;async function vS(e,t){if(Qe(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}Xe(t.target),C(t,"analyze_prepare",{mediaItemId:e,target:t.target,wait:!!t.wait});let r=A("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,w(i)),S(w(i))}if(C(t,"analyze_ready",{mediaItemId:e,status:n.status,alreadyRunning:!!n.alreadyRunning}),!t.wait){t.json||console.log(`
11
+ Run \`cueframe clips ${e}\` to check results.`);return}let o=A("Waiting for analysis to complete\u2026",t.json),s=Date.now();for(;;){await new Promise(i=>setTimeout(i,_r)),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`),m.UserError),S(m.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((d,c)=>{let f=(d.trim.end-d.trim.start).toFixed(1);console.log(`
12
+ ${c+1}. ${d.title} (${d.id})`),console.log(` ${d.trim.start.toFixed(1)}s \u2013 ${d.trim.end.toFixed(1)}s (${f}s) score: ${d.score}`),console.log(` ${d.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,I as b,L as c,a as d,O as e,st as f,P as g,Y as h,re as i,be as j,Ee as k,Ke as l,Je as m,Tr as n,m as o,w as p,XP as q,S as r,rS as s,oS as t,nS as u,Nr as v,Xe as w,T as x,A as y,C as z,uS as A,M as B,U as C,lS as D,Qe as E,vS as F};