mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
feat(media-use): resolve engine + BGM/SFX/image/icon providers (#1683)
* feat(media-use): core infrastructure — manifest, cache, adopt, probe Foundation for media-use — the media resolution layer for HyperFrames. - manifest.mjs: JSONL read/write/find for .media/manifest.jsonl - index-gen.mjs: regenerate agent-readable index.md from manifest - cache.mjs: content-addressed global cache at ~/.media/ (SHA-256, sentinel) - freeze.mjs: download URL or copy local file to .media/ - probe.mjs: extract duration/dimensions via ffprobe - adopt.mjs: scan assets/ directory, register existing files with metadata - 19 passing tests (manifest round-trip, cache, promote, index generation) * fix(media-use): oxfmt formatting + cap freeze download size Format adopt/cache/probe/manifest.test (CI oxfmt --check gate). Cap freezeUrl downloads at 256MB so a hostile/runaway URL can't fill the disk (addresses CodeQL #670: network data written to file). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(media-use): resolve engine + all providers + brand from frame.md - resolve.mjs: cheapest-first cascade - BGM/SFX via heygen --headers, Image/Icon via heygen asset search - Brand tokens from frame.md / design.md (local, no API) - SKILL.md: full agent docs + hyperframes.dev/design redirect - Router skill + workflow skill references * fix(media-use): oxfmt formatting for resolve + providers Format brand/heygen-search/providers/sfx providers + resolve.mjs (CI oxfmt --check gate). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(media-use): align providers with the real heygen CLI surface (v0.1.6) Verified live against the official Go `heygen` CLI v0.1.6 with a valid key: - Caller attribution: pass `--headers 'X-HeyGen-Client-Source: media-use'` (the allowlisted flag the CLI added for media-use in v0.1.6). The old `--x-source media-use` was never a real flag and broke every call. - Command is `asset search` (the `list` leaf was dropped in v0.1.6), not `asset search list`. - `--min-score` is sent server-side: honored by `audio sounds list`, but the `asset search` backend rejects it and returns no score field, so only the audio providers pass it (image/icon don't). - Drop hardcoded `ext` so resolve.mjs derives it from the URL: catalog icons are .png (not .svg), some BGM is .wav (not .mp3). Also: surface CLI/auth failures on stderr instead of swallowing them as 'no results', carry icon width/height through, and document the heygen CLI install + >= v0.1.6 requirement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
73f6d3e5be
commit
b2dc353725
@@ -0,0 +1,45 @@
|
||||
import { execSync } from "node:child_process";
|
||||
|
||||
export function heygenSearch(subcommand, query, { type, limit = 5, minScore } = {}) {
|
||||
const q = query.replace(/'/g, "'\\''");
|
||||
// Tag the caller via the CLI's allowlisted attribution header (heygen >= v0.1.6).
|
||||
const parts = [
|
||||
`heygen --headers 'X-HeyGen-Client-Source: media-use' ${subcommand} --query '${q}'`,
|
||||
];
|
||||
if (type) parts.push(`--type ${type}`);
|
||||
parts.push(`--limit ${limit}`);
|
||||
// Server-side score floor. Honored by `audio sounds list`; the `asset search`
|
||||
// backend rejects it, so only audio providers pass minScore (see image-provider).
|
||||
if (minScore != null) parts.push(`--min-score ${minScore}`);
|
||||
|
||||
let out;
|
||||
try {
|
||||
out = execSync(parts.join(" "), {
|
||||
encoding: "utf8",
|
||||
timeout: 15000,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
} catch (err) {
|
||||
// Don't swallow a broken command / auth failure as "no results" — that turns
|
||||
// a typo or expired key into a silent dead end. Surface it, then give up.
|
||||
const detail = err.stderr?.toString().trim() || err.stdout?.toString().trim() || err.message;
|
||||
console.error(`media-use: \`heygen ${subcommand}\` failed: ${detail}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(out);
|
||||
} catch {
|
||||
console.error(`media-use: \`heygen ${subcommand}\` returned non-JSON output`);
|
||||
return null;
|
||||
}
|
||||
if (parsed?.error) {
|
||||
const e = parsed.error;
|
||||
console.error(`media-use: \`heygen ${subcommand}\` error: ${e.message ?? JSON.stringify(e)}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = parsed?.data;
|
||||
return Array.isArray(data) && data.length > 0 ? data : null;
|
||||
}
|
||||
Reference in New Issue
Block a user