6539 Commits
Author SHA1 Message Date
Miguel Ángel 2439b62acd chore: release v0.8.223 (#6869) v0.8.223 2026-10-30 19:11:14 -07:00
Vance IngallsandClaude Opus 5.5 5e4f5aefb5 fix(core): motion blur preview no longer slows down later in the timeline (#6865)
* fix(core): motion blur preview no longer slows down later in the timeline

With data-motion-blur-events="on", which Studio's Subtle and Strong write,
both blur tiers ran timeline callbacks at every per-frame pose read. Each
frame's reads step back from half a shutter ahead to the frame, so a
callback that keeps state and replays from zero on a backward seek (a
ripple simulation, for example) redid its whole history most frames, and
the cost grew with the playhead.

The mover scan still runs callbacks, so motion set from a render(t)
callback is still found. With events on, it also scans once without them,
and the per-frame reads run callbacks only when the two scans disagree.
The eventful scan runs first, so tweens take their start values after the
callbacks before them and a one-off call fires as often as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(core): keep the motion blur comments to the invariant

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(core): motion blur reads run callbacks when a callback moves any box

Comparing which elements each scan finds missed a callback that pans a
mover's ancestor while a tween also changes that ancestor: both scans
found the same movers and the same changing elements, so the reads left
the pan out. The scans now compare every changing element's box at each
step, and the reads run callbacks when any step differs.

Raises @hyperframes/core's unpacked size budget to the measured size plus
the usual 5%: main already sat 0.98% over the old budget, and this change
adds 1,232 bytes, which tipped it past the 1% tolerance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(core): silent motion blur reads land back on the frame as its own seek left it

After silent pose reads, the restore seek back to the frame left GSAP in a
different state than the frame's own eventful seek did:

- A step exactly on the frame (a .call() or set) was re-armed, so the next
  frame fired it again. Calls fired 2-5 times per crossing, and a toggle
  could end inverted.
- In renders, which keep no GSAP structure, landing back on the frame from
  later skipped same-time steps' authored order, so the frame showed the
  first of two sets instead of the last.

Events-off blur always read silently and had both. This PR moves events-on
roots without callback-driven motion (the Studio default) onto that path,
so both are fixed here.

The host's new holdFrame snapshots every landing mark on the root and scene
timelines before the reads, and its restore seeks back silently, redraws in
authored order where there is no structure, and puts the marks back. Each
call now fires once per frame crossing, as without blur, and same-time sets
land as authored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(core): a held render frame draws its scenes first, so the root lands last

holdFrame redrew the root and then the scenes, the reverse of the frame's
own seek. When a scene and the root tween one property, the frame landed
on the scene's value instead of the root's.

The hold and landing move into the GSAP adapter as holdFrameMarks, which
takes the scenes and the root separately, so the order lives in one place
a real-GSAP test can pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 18:21:27 -07:00
WaterrrForeverandMiguel Angel Simon Sierra f2358315e5 feat(skills): re-land reverse any video on the HyperFrames plan, with clearer credit wording (#6833)
* fix(cli,skills): say a step's credits are its total, and keep cost out of retries

An out-of-credits refusal named what the step needs, and an agent read
that as the shortfall. It now says the number is the step's total.

After its last try, an agent told the person what was spent and what
another try would cost. The HeyGen reference now says not to.

* fix(cli): plan avatar credits from the HyperFrames price rows

An avatar's credits came from its old API price, about five times what
the plan charges, so --max-credits refused calls that fit and a top-up
asked for too much. They now use the Avatar IV photo row plus the
general avatar video row, 950 credits a minute.

* fix(cli): pin the avatar price test and keep pricing under the comment share

* fix(cli): plan avatar seconds on the Avatar IV row alone

The general avatar row is only checked at admission and billed on
seconds left after Avatar IV, so adding it to every second made a 15 s
script plan at 238 instead of 200 and a 220 limit refuse a call that fits.

* fix(cli): the credits link opens the web plan page, which is live

* test(cli): pin the production credits link too

* chore(skills): regenerate the skills manifest after merging main

* docs(cli): keep the person measure's doc comments to four lines

* docs(cli): keep the measure doc comments to four lines

* docs(cli): keep the measure comment lines to 120 characters

---------

Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
2026-10-31 00:47:54 +00:00
Vance IngallsandClaude Opus 5.5 5169422a8a fix(lint): the podcast-lanes.html page Desktop writes is not a second root composition (#6809)
* fix(lint): the podcast-lanes.html page Desktop writes is not a second root composition

HyperFrames Desktop's podcast edit writes its camera lanes page, podcast-lanes.html,
at the project root beside index.html: Studio reads no composition inside a dot
folder, and Desktop opens the page directly as its own view. index.html never mounts
it and no render plays it, but multiple_root_compositions fails lint and check on
every podcast project, and its fix hint tells an agent to remove the file. Exempt it
the way caption-skin.html already is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(lint): name the pages opened beside index.html instead of commenting them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 17:36:28 -07:00
Miguel Ángel 443ded4261 fix(player): preview voice no longer goes silent while other tracks play (#6859)
* fix(core): audio that decodes short plays from its element in preview

* fix(core): keep the decoded copy when the element's duration is unknown

* fix(player): preview pauses with Buffering until every track due can play

* fix(core): keep the transport awake while it buffers

* fix(core): wait only for tracks the clock would also treat as playable

* test(core): buffering fixture pauses like a browser, with a pause event

* fix(core): hold for a clip only after media sync has asked it to play

* test(core): hold lands on the frame a slow tick skips into a clip with no data

* fix(core): a held clip counts as ready once it has data buffered ahead
2026-10-30 21:25:28 +00:00
Ular Kimsanov 4cee7be834 docs: one Docs menu and Catalog in the top bar (#6860)
Make a video, Studio app and Developers move into a Docs menu (each keeps its
own sidebar), with Free lessons, Community and the app changelog under them;
Catalog stays a tab. The top-bar copy of Ask Assistant goes (Ask stays in
search and the page's bottom bar); the logo opens the homepage; the button
reads Download.
2026-10-30 21:18:07 +00:00
Miguel Ángel 359b6c8a38 feat(core): playback health reports how long a video on screen showed no moving picture (#6856)
* feat(core): playback health reports how long a video on screen showed no moving picture

* fix(core): a frozen picture is judged by the clip's own timing, not the film's

* style(core): shorten a test comment under the line limit

* fix(core): the frozen-picture check reads a video from any realm

* refactor(core): cut the frozen-picture comments the comment ratchet counts
2026-10-30 18:48:25 +00:00
Miguel Ángel 9b0df610cc perf(studio): a long timeline no longer lays itself out on every render while it settles (#6855)
* perf(studio): a long timeline no longer lays itself out on every render while it settles

* perf(studio): compare row data with sameData and drop the added comments
2026-10-30 18:30:14 +00:00
Miguel Ángel e342a90991 fix(history): reading a project's history no longer rewrites its record (#6832)
* fix(history): reading a project's history no longer rewrites its record

* fix(history): opening a recorded project still counts as a use
2026-10-30 18:30:07 +00:00
Miguel Ángel 0708f6ca7d fix(lint): a timeline registered in a local script file counts as registered (#6829)
* fix(lint): a timeline registered in a local script file counts as registered

* fix(lint): a module script file is read as a module

* style(lint): format the module script check
2026-10-30 18:29:58 +00:00
Miguel Ángel ef9155fee1 fix(cli): say stdin was empty when a JSON flag reads - and nothing is piped (#6852) 2026-10-30 18:29:50 +00:00
Miguel Ángel aafbd96b77 fix(core): same-time sets at 0 land in authored order on the first frame (#6851) 2026-10-30 18:29:40 +00:00
Miguel Ángel 80f9350da2 fix(cli): remove-background gathers each decoded frame in linear time (#6850) 2026-10-30 18:29:31 +00:00
Miguel Ángel 6aa9c78bd8 fix(cli): exit-time telemetry no longer loses a render's events on Windows (#6847)
* fix(cli): exit-time telemetry no longer loses a render's events on Windows

* fix(cli): telemetry smoke stand-in reads the batch file; format the warning
2026-10-30 18:29:19 +00:00
Miguel Ángel 16e2e4c6b5 fix(cli): read BOM-prefixed JSON files for timeline plans, grades and motion specs (#6845)
* fix(cli): read BOM-prefixed JSON files for timeline plans, grades and motion specs

* fix(cli): read BOM-prefixed files for render --batch, lambda policy and transcripts

* test(cli): drop the batch BOM test #6605 already covers

* fix(cli): decodeJsonText is only used inside jsonFlag.ts

* fix(cli): drop a fallow suppression the export no longer needs
2026-10-30 18:29:08 +00:00
Miguel Ángel 3d942ee921 fix(producer): HDR renders report their encoder wait in render telemetry (#6841) 2026-10-30 18:28:46 +00:00
Miguel Ángel e28dbe4ce4 chore: release v0.8.222 (#6846) v0.8.222 2026-10-30 18:04:36 +00:00
Jerrai 1116077dab fix(cli): capture treats only 192.0.0.0/24 and 192.0.2.0/24 as reserved, via one shared list (#6853)
* fix(cli): capture's public-address check uses the engine's list; 192.0/16 is not all reserved

Only 192.0.0.0/24 and 192.0.2.0/24 are special-use. The capture proxy blocked all of
192.0.0.0/16, so sites on WordPress VIP (192.0.64.0/18, e.g. nasa.gov at 192.0.66.108)
failed every capture with net::ERR_TUNNEL_CONNECTION_FAILED. isPublicIPv4 now reads the
engine's isBlockedNetworkHost, so capture and asset downloads share one list.

— Jerrai (cutroom-debug)

* refactor(engine): one special-use network list, in a light subpath capture imports

Importing all of @hyperframes/engine into capture's publicNetwork slowed the lookup child's
start-up past publicNetwork.process.test's 6 s mid-lookup exit. The list and
isBlockedNetworkHost move to engine/src/utils/networkPolicy.ts, exported as
@hyperframes/engine/network-policy; urlDownloader and the engine index read it there.

— Jerrai (cutroom-debug)

* test(engine): pin 192.0.0.0/24 and 192.0.2.0/24 blocked, the rest of 192.0/16 public

— Jerrai (cutroom-debug)

* fix(cli): alias the engine's network-policy subpath in the CLI bundle

esbuild's root alias rewrote @hyperframes/engine/network-policy to src/index.ts/network-policy;
the exact-subpath list now carries it. The publicNetwork docstring is cut to keep the file's
comment share under its base.

— Jerrai (cutroom-debug)
2026-10-30 16:21:34 +00:00
kevin ee7059d4d2 fix(parsers): treat any URL scheme as non-relative in isNonRelativeUrl (#6815)
* fix(parsers): treat any URL scheme as non-relative in isNonRelativeUrl

* fix(parsers): keep assetPaths.ts's comment share from rising
2026-10-30 16:04:07 +00:00
Muzzy5150 64d190e34f fix(core): prevent Figma motion property key collisions (#6800) 2026-10-30 16:04:03 +00:00
Akshar Patel 3245b769aa fix(studio-server): keep long file paths from blocking saves (#6611) 2026-10-30 16:03:58 +00:00
Akshar Patel 4cabfd18a2 fix(cli): render batches read PowerShell JSON files (#6605) 2026-10-30 16:03:54 +00:00
Akshar Patel b54de2c9e1 fix(parsers): validate slideshow time bounds before playback (#6514) 2026-10-30 16:03:50 +00:00
kevin 0a304f2aa6 fix(cli): read a comment after an empty .env value as no value (#6497) 2026-10-30 16:03:46 +00:00
NavpreetSSidhu f64b028223 fix(cli): count line_unread words from the block's rendered text (#6456) 2026-10-30 16:03:41 +00:00
Akshar Patel fc3d0a5fce fix(core): load responsive images from their scene (#6399) 2026-10-30 16:03:37 +00:00
kevin a6dec0701f fix(media-use): keep the network cause in Gemini TTS errors (#5568) 2026-10-30 16:03:24 +00:00
Ular Kimsanov a06fdfe26e docs(catalog): put each item page's title, description and Docs text in the server HTML (#6711)
* docs(catalog): put each item page's title, description and Docs text in the server HTML

Mintlify renders snippet components in the browser only, so everything inside
CatalogDetail (title, standfirst, the Docs tab) was missing from the HTML search
engines read: 448 catalog pages served Googlebot no body text. The generator now
writes the H1 and standfirst as page markup above the component and the Docs tab
as page markup after it, shown with that tab (docs/custom.css). The component no
longer draws its own title. Pages patched structurally only; registry drift on 14
pages is left for a regeneration of its own.

* docs(catalog): keep the title's top spacing the component gave it

* fix(docs): catalog titles and descriptions keep markdown markers literal

MDX reads text inside the static <h1> and <p> as inline markdown, so @_blue_sweater_
rendered as italic blue_sweater. mdxText now writes backslash, backtick, * _ [ ] ~ as
character references too, with a unit test; the four affected pages are re-escaped.
2026-10-30 15:48:25 +00:00
Ular Kimsanov 28181602fe docs(quickstart): drop the stale 'if you are on Windows' line (#6803) 2026-10-30 15:07:33 +00:00
Miguel Ángel 6cddd1a240 feat(lint): warn when a url() in a linked stylesheet does not resolve beside it (#6844)
* feat(lint): warn when a url() in a linked stylesheet does not resolve beside it

* fix(lint): a percent-encoded url() in a linked stylesheet resolves like the browser does
2026-10-30 14:58:57 +00:00
Miguel Ángel 4da50e2218 feat(telemetry): render_complete splits capture time into seek, page, screenshot and encoder wait (#6839) 2026-10-30 14:55:06 +00:00
Miguel Ángel 5a164fb369 feat(cli): render --start and --end render only that span of the film as its own MP4 (#6834)
* feat(cli): render --start and --end render only that span of the film as its own MP4

The span reuses the chunked render path, so frames are captured at their absolute times and sub-composition timing matches a full render.

* chore(producer): shorten the renderSpan comment

* fix(producer): a cancelled span render stops, and its real-render test runs in the integration lane

renderSpan checks the abort signal before each chunk part and before the stitch. The real-render tests move to their own file listed in the integration lane.

* chore(producer): put the renderSpan doc comment back above renderSpan
2026-10-30 14:45:43 +00:00
James RussoandClaude Opus 5.5 b45e602faa revert: feat(skills): reverse any video (#6754) (#6840)
* revert: feat(skills): reverse any video (#6754)

Keep the reverse-any-video skill and its CLI billing commands out of main until
web subscriptions are live (/pricing and /account/plan return 404 today).
Re-land together with #6833 once those pages ship.

This reverts commit cb2389cf35.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(scripts): allow the #6754 revert deletions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-30 14:32:26 +00:00
Miguel Ángel 746ce956b3 test(history): the write-timing test no longer depends on how late its timers fire (#6837)
* test(history): the write-timing test no longer depends on how late its timers fire

* test(history): the write-timing test gives its turn a wide idle limit
2026-10-30 14:11:42 +00:00
Miguel Ángel 4ba01be151 fix(cli): history show --diff names a changed video or audio file instead of refusing (#6836)
* fix(cli): history show --diff names a changed video or audio file instead of refusing

* fix(cli): history show --diff names a changed video or audio file instead of refusing
2026-10-30 14:11:35 +00:00
Miguel Ángel 3ebf888fb6 fix(cli): point a brace-stripped JSON flag value at the file and stdin forms (#6838)
* fix(cli): point a brace-stripped JSON flag value at the file and stdin forms

* fix(cli): share the brace-stripped JSON hint with --variables and skip drive paths
2026-10-30 14:07:40 +00:00
Miguel Ángel 6a8c064fb9 fix(producer): render telemetry names content gates instead of calling them disabled (#6835) 2026-10-30 14:02:01 +00:00
Miguel Ángel 6f2b072275 fix(cli): --variables-file and --variables <path> read the file again (#6831)
* fix(cli): --variables-file and --variables <path> read the file again

* fix(cli): drop the comment the typed merge already says
2026-10-30 13:39:35 +00:00
cb2389cf35 feat(skills): reverse any video on the HyperFrames plan (#6754)
* feat(skills): reverse any video on the HyperFrames plan

Reverse rebuilds a video as an editable HyperFrames project and re-shoots its
people with HeyGen. It runs for a person signed in on HyperFrames Pro; Free is
told it is a Pro feature and given the upgrade step.

- skills: reverse-any-video; media-use is the one gate for HeyGen calls
  (sign-in, credits, refusals)
- cli: media-use generate (image, video shot, avatar, voice, music) with --plan
  pricing and --max-credits; measure, diff and analyze for the rebuild; the
  HyperFrames plan in auth status; billing subscribe and top-up wait on the
  plans or credits page
- remotion-to-hyperframes compares with `hyperframes diff` instead of its own
  shell scripts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(skills): satisfy CI gates for reverse-any-video

- docs: list diff, measure, analyze and billing in "Find your command" in
  docs/packages/cli.mdx, each with its own section.
- skills: bring media-use/SKILL.md under its 5120 B budget by pointing setup,
  direct-recipe and treatment detail at the references that already hold it;
  the sign-in, credits, --max-credits and billing rules stay in SKILL.md.
- comments: register transcript.json and REVERSE.md as project files for the
  citation checker, and drop a history note from face.test.ts.
- comments: cut restating prose or move it into names so every changed file is
  at or under its comment share. Allowlist the two deleted remotion scripts in
  check-no-main-deletions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli): terminate measure's ffprobe options with --

probeVideo passed the input path straight after its options, so a path
starting with "-" would be read as a flag; the producer's ffprobe argv
contract test failed on it. runFfmpeg's fixed flags move to a constant
so the contract no longer mistakes that ffmpeg wrapper for a probe.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(cli): split diff's video tests into three files under CI's per-file limit

The file took ~131 s on CI against the flake gate's 120 s, and its heaviest test (four
comparisons) hit the 20 s per-test limit. The video tests now live in three files sharing
diff.test-helpers.ts, and that test is two tests of two comparisons each.

analyze reads each part once and checks the bytes it read, instead of a stat then a read
(CodeQL js/file-system-race).

* fix(skills,cli): one credits rule; ask before dropping a step that won't fit

On dev with a 100-credit limit the agent priced a re-shoot with --plan and dropped it without
asking (J5), and in J6 it told the person a price. SKILL.md's Credits rule now covers both:
--plan is for the agent, and when a step won't fit (a --plan over what is left, or a refused
call) the agent says what doesn't fit and asks before dropping or shrinking it.
setup-providers.md's older confirm-before-paying rule points to it.

--plan now runs the same checks as the real call (checkRequest), so it no longer prices a
request that would be refused. The re-shoot recipe in people.md gains the --prompt it needs.
heygen.md: a sign-in also makes images, and --plan's usd is the API charge rounded to $1/60
while its credits come from the list price.

* fix(cli): auth status drops 'balance unavailable' above the plan's credits; sign-in page title

* test(cli): keep diff's video tests inside the flake gate's limits

Under the gate's CPU contention every diff test needing face detection or
optical flow paid opencv.js's 11 MB download and WebAssembly start-up, and
every diffVideos call wrote four worst-moment pictures (about 28 ffmpeg runs)
no assertion read. Tests ran 21-28 s against the 20 s limit.

- loadOpenCvFirst() stages opencv.js in a beforeAll (from this machine's
  cache, a temp copy kept between runs, else the network).
- diffVerdicts() runs diffVideos with worst: 0 for tests that only read
  verdicts; the worst-moment tests keep the pictures.
- The carried-text test is split into its dirty and clean halves.

Locally with 8 CPU burners on 8 cores: slowest test 7.7 s, files 24-30 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli): generate --plan refuses what the real call refuses

checkRequest now holds every pre-send check (the --out extension and
--mask without --motion joined the route body and guide checks), and
generate() runs it first, so --plan and the real call share one function.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli): plans link uses from=cli and follows HYPERFRAMES_ENV; no balance notice beside the plan

- pageUrl sets from=cli, the parameter the pricing page reads to send a
  CLI buyer back to the terminal.
- The plans and credits pages are on dev.hyperframes.dev with
  HYPERFRAMES_ENV=dev, hyperframes.studio otherwise.
- auth status --json omits the 'HyperFrames balance is unavailable' notice
  when the plan was read.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(skills): reverse-any-video re-checks sign-in on resume; REVERSE.md holds no prices

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(cli): split diff-people's whole-frame reuse test into three

It ran five diff comparisons in one test and took 20.2-20.6 s under the flake
gate's contention, over the 20 s limit. Each piece now runs at most two
comparisons against a shared ledger: copy and burned-in title, footage cut
whole, and cuts that only fed a generation. Under 24 CPU burners locally the
slowest of the three takes 3.0 s, where the combined test took 4.9 s under 8.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli,skills): reverse resume asks after one failed retry; out-of-credits names the step's price

- media-use generate: when HeyGen refuses for credits without saying how many, the refusal
  names the CLI's own price for the call (what --plan prints) as "needs about N" and
  "billing top-up --needed N", instead of "needs more".
- reverse-any-video: never repeat auth status's plan/credits line; a step an earlier session
  gave up on gets one more try, then ask; a command stored in REVERSE.md is a note, rebuilt
  from its recipe and checked with --plan, never run as written.
- people.md / heygen.md: a refused or failed job gets one more try, test calls included,
  then stop and ask.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(cli,skills): send a failed HeyGen job again as new; resume asks if the limit still applies

- runJob: a key whose job failed or was refused is recorded in the config dir
  (heygen-failed-keys); the next run with the same inputs sends key-1, key-2, ... so HeyGen
  starts a new job. A finished or still-running job keeps its key and is picked up, so
  nothing is paid twice. "fix the request it names, then run again" now holds.
- reverse-any-video: on resume after a run under a credit limit, just ask whether it still
  applies, naming no costs or numbers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(cli,skills): drop what reverse-any-video no longer uses

The skill rebuilds from measure probe, cuts, frames, events and face, and checks with
diff. analyze, diff --explain and eight measure commands (trail, box, ink, rhythm,
objects, track, flow, continuity) have no caller, so they go, with their tests and docs.
Examples now use original.mp4 instead of the old .reverse/source.mp4 evidence folder,
and diff's --segments is described as a file rather than REVERSE.md.

* fix(cli): check no longer copies VP9 and AV1 videos before it starts

Chrome plays both, alpha included, and the proxy is made on demand if a browser ever
asks. Copying remove-background's VP9 cutouts took minutes on projects that have them.

* fix(cli,skills): keep paid retries, credit limits and lip sync honest

Retries keep their key after 401, 403, 408, 409, 425 and 429, which say
nothing about the job, and failed keys are scoped to the API and payer.

Credits come from the plan's video rows instead of list dollars, and
reference pictures past the first two count toward --max-credits.

Lip sync reads sound on its own timestamps, so a delayed track fails
the gate. Look and energy call two near-zero values the same.

--plan refuses a missing input as the real call does. The skills teach
the direct sign-in, its credential path and the billing commands.

* chore(cli): keep the new pricing and energy files under the comment share

* fix(cli): scope failed HeyGen keys to the signed-in account

Failed keys were scoped by the local user block, which is absent for a
host's token and display-only otherwise, so two accounts could share a
scope and one could start a second paid job.

The scope now comes from the account /v3/users/me reports for the token
in use. When that cannot be told, no failure is recorded and the key
stays the same.

* fix(cli): fix a job's sender when it starts

Failure scope was looked up again after polling, so a sign-in during a
job could record one account's failure under another and rotate its
finished key. The credential is now read once per job: it signs the POST
and owns any failure, even if someone else signs in meanwhile.

Prefer username to email, since /v3/users/me returns no user id.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: James <james.russo@heygen.com>
2026-10-30 13:24:02 +00:00
Miguel Ángel bf47178937 fix(lint): a font the project's root stylesheet declares counts for its sub-compositions (#6827)
* fix(lint): a font the project's root stylesheet declares counts for its sub-compositions

* fix(lint): Google Fonts links count too, and only for files the root mounts
2026-10-30 13:14:22 +00:00
Miguel Ángel 8142d6d59f test(cli): capture watchdog tests use a fake output folder outside the temp dir (#6828) 2026-10-30 13:04:11 +00:00
Miguel Ángel ef2159fe8c fix(cli): capture retries without WebGL when the page stops answering under software GL (#6821)
* fix(cli): capture retries without WebGL when the page stops answering under software GL

* style(cli): format the capture stall retry test

* style(cli): shorten the stall watcher comment

* fix(cli): drop the comment line the comment ratchet refuses

* test(cli): the stall retry tests use a fake output path that is not a temp file
2026-10-30 13:03:12 +00:00
Miguel Ángel b20d0a62ce fix(studio): a split at a clip's edge leaves the file unchanged (#6826)
* fix(studio): a split at a clip's edge leaves the file unchanged

* fix(studio): keep the split margin's doc within the comment width

* chore(studio-server): keep the split margin's comments within the file's share
2026-10-30 13:01:29 +00:00
Miguel Ángel 88d8e5b490 fix(cli): check and snapshot load GSAP from the bundled copy, not jsDelivr (#6824)
* fix(cli): check and snapshot load GSAP from the bundled copy, not jsDelivr

* test(cli): bundled GSAP loads on a page whose own requests interception answers
2026-10-30 12:54:06 +00:00
Miguel Ángel bb2c8142fd perf(studio-server): add createProjectSignatureAsync so project open stops blocking the loop (#6825)
Same signature as the synchronous walk, with the directory walk and file reads awaited.
2026-10-30 12:26:29 +00:00
Miguel Ángel 01783f3757 feat(cli): review notes name the command that reviews the cuts inside a sub-composition (#6820)
* feat(cli): review notes name the command that reviews the cuts inside a sub-composition

* fix(cli): the review note fires only for a host with cuts inside it
2026-10-30 11:55:05 +00:00
Miguel Ángel 44ee07a2da fix(cli): check drops a request a network change cut when the file loads again (#6823)
* fix(cli): check drops a request a network change cut when the file loads again

* style(cli): format the network-change check fix

* fix(cli): drop the comment the ratchet would count

* fix(cli): a check out of time drops the requests a network change cut
2026-10-30 11:32:18 +00:00
Miguel Ángel 536209da07 fix(producer): report extract_video progress while ffmpeg extracts frames (#6822)
Frames ffmpeg has written now reach the render's stage progress, so a long source video no longer leaves the render silent between extract_video and capture.
2026-10-30 11:23:59 +00:00
Miguel Ángel d4a866d612 fix(cli): check no longer calls text occluded by a cover that a CSS mask paints through (#6818)
* fix(cli): check no longer calls text occluded by a cover that a CSS mask paints through

* fix(cli): a mask on a wrapper around both the text and the cover does not hide the cover

* style(cli): format the mask walk
2026-10-30 10:56:15 +00:00
Miguel Ángel 315969cda0 fix(cli): render names the FFmpeg that has no libx264 and how to point at another (#6819) 2026-10-30 10:52:46 +00:00