Commit Graph
2138 Commits
Author SHA1 Message Date
Miguel Ángel 3aaed65ef6 fix(check): the analysis restarts the idle window with every call it makes (#6919)
* fix(check): the analysis restarts the idle window with every call it makes

* test(check): runAuditGrid's analysis must use the progress-reporting driver
2026-11-03 19:47:13 +00:00
Wenbo ZhuandClaude Opus 5.5 a5a6121332 fix(cli): don't invent a purchase link when the server withholds upgrade_url (#7031)
reverse/start answers upgrade_url: null when no plan can be bought right
now. The CLI treated that like a missing field and built its own plans
link, so a Free account under gate "block" was sent to a page where it
can't buy. Now null means no link anywhere: the JSON prints
upgrade_url: null and subscribe_command: null (billing subscribe would
open that same plans page), the refusal says a plan can't be purchased
right now instead of naming the subscribe command, and the skill runs
nothing and passes on no link. Only an absent field (an older server)
falls back to the plans page; a string is used as is.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:47:05 +00:00
WaterrrForeverandClaude Opus 5.5 faae6017dd refactor(cli): templates pull unpacks the verified pack from memory (#7084)
The pack was written to a temporary file before tar read it. tar now
reads the checked bytes on stdin, so nothing downloaded is written to
disk before it is unpacked.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:14 +00:00
WaterrrForever 12ce8c2ffd chore: release v0.9.9 (#7095) 2026-11-03 11:28:41 -05:00
Wenbo ZhuandClaude Opus 5.5 b2acef5869 fix(cli): no auto-update across 0.x minors; install skills at the CLI's release tag (#7013)
* fix(cli): no auto-update across 0.x minors; install skills at the CLI's release tag

- autoUpdate: before 1.0 a minor bump counts as a major one, so 0.8.x -> 0.9.x
  is a notice, not a silent background install. From 1.0 on, the major alone.
- skills: `skills update` / bare `skills` / `init` install from
  heygen-com/hyperframes#v<VERSION>, and `skills check` plus the background
  freshness nudge read the manifest at the same tag. A build the repo has no
  tag for (dev build) falls back to main, as before.
- skills: run the upstream installer as `npx skills@1.7.4` instead of an
  unpinned `npx skills`.

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

* fix(cli): keep the comment share of the touched files from rising

Comment ratchet: trim the comments added in the previous commit. No code change.

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

* fix(cli): pass the CLI version into the skills check instead of importing it

scripts/clawhub-unlist-retired.mjs loads skillsManifest.ts from source under
plain node, which cannot resolve a relative `../version.js` import. Callers now
pass `cliVersion` (and skillsSourceRef takes it as an argument), so the module
keeps importing only node builtins.

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

* fix(cli): read skills at the CLI's tag without a probe; pin skills@1.5.13

- A release build reads the manifest at its own tag directly (publish pushes
  the tag before npm publish). Only a 404 for that manifest falls back to main;
  a timeout, missing git or proxy error now surfaces instead of quietly
  comparing against main, so the background nudge can't cache a false
  "outdated" count.
- checkSkills returns the ref it read, and skills update installs from that
  same ref, so check and install can't disagree within one run.
- Pin skills@1.5.13 (it parses `#<ref>` too) so the pin matches the version
  agentDirs.generated.ts and the lock-path notes were checked against.

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

* refactor(cli): split the tag and main manifest fetches

Fallow flagged fetchRemoteManifest's CRAP score (31.6 > 30). The tag fetch
(404 is the only fallback to main) and the SHA-pinned main fetch are now their
own functions. No behaviour change.

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

* fix(cli): never auto-upgrade a Homebrew install

`brew upgrade hyperframes` installs whatever formula the tap holds, so a
background run scheduled for an allowed patch could still cross a 0.x minor.
Homebrew installs now only get the update notice naming `brew upgrade`.
A new test drives the scheduler through the real installer detection and
installer script: no spawn on Homebrew, a versioned npm install for a patch.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 13:21:39 +00:00
WaterrrForeverandClaude Opus 5.5 2daedcdafc feat(skills): style templates on the HyperFrames plan (#6842)
* 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.

* feat(skills): creator templates on the HyperFrames plan

A Pro account asks for a video in a creator's format and the agent pulls that
template on demand. The packs sit in the private bucket behind the plan-gated
bundle route, so a Free account gets a 402 and the upgrade step. A pull costs
no credits; making the film spends them as Reverse does.

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

* feat(skills): make creator-remix the one template skill

SKILL.md holds the catalog, the Pro openings, the pull and the credit
rules. references/remix.md is how to make the episode, from Desktop's
creator-remix with only what the app alone has swapped for the CLI.
The packs now hold only the template, so their hashes change.

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

* feat(skills): the creator-remix skill and its packs

SKILL.md holds the catalog, the Pro openings, the pull and the credit
rules. references/remix.md is how to make the episode, from Desktop's
creator-remix with only what the app alone has swapped for the CLI.
The packs now hold only the template, so their hashes change.

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

* fix(skills): word creator-remix's sign-in steps the way media-use does

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

* feat(skills): a creator-remix presenter runs on the plan by default

The person's own HeyGen avatar is recommended, not required: without
one, 小Lin's presenter is made with HeyGen Video 1 from their photo.

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

* feat(cli): pin template packs whose voice bills the plan first

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

* fix(cli): offload media named inside template tags

References in a composition's <template> were never rewritten, because the DOM
query stops at the tag and template.content does not serialize, so the file stayed
in the zip. A stem matched as a plain word and a same-named file elsewhere counted
as a mention too. A 5-minute presented film went from 196 MB to 71 MB.

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

* feat(cli): lipsync, and avatars that speak a finished voice

Video 1 takes audio as a reference and re-paces it, so a shot's lips follow its
own track and drift up to a second from the voice. generate --type lipsync redoes
the mouth to the exact voice. generate --type avatar takes --audio, and --avatar
for the person's own look, so the lips land on the voice from one job.

Also moves the plan rows to the 2026-10-30 price book, estimates a voice's credits
so --max-credits can hold it, logs jobs from a folder with no project, and describes
the resolve flags.

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

* feat(skills): presenters go avatar first, and a voice can be stock

The person's own avatar, then Avatar IV from their photo, then Video 1 with
lipsync. With no clone or recording, a stock voice named in the credits. Pins the
five rebuilt packs. The archive test keeps its ../ under GNU tar with -P.

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

* test(cli): fix avatar price and sfx provider tests, trim comments

A wav gives the avatar price test an exact length on every platform. The
sfx tests now expect HeyGen first. Comment share is back under the base.

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

* fix(core): read a font shorthand whose size nests parentheses

`font: calc(var(--size) * 1px)/1 "X"` cut at the first closing parenthesis, so a
bad family name failed the render.

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

* fix(cli): one ledger row per job, and search skips a template's own pictures

A job done at once logs one row, transcribe logs to the project, and resolve no
longer offers a component's file for a search. --reuse and --provider get help text.

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

* feat(skills): pin the tested template packs, and a board needs no voice

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

* test(cli): read the transcribe ledger row as JSON, for Windows paths

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

* chore(cli): pin the Big Questions pack without the film length check

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

* docs(skills): call them style templates, and the docs example pulls a real slug

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

* chore(cli): pin the cleaned template packs

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

* docs(skills): drop the stock-presenter ban and the no-spend-before-storyboard rule

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

* chore(cli): pin the Paper Trail and Long Story Short packs without the stock-presenter ban

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

* feat(skills): rename creator-remix to style-remix, and the five templates to names that say the look

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

* feat(skills): style-remix lists the five templates when none is named

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

* chore(cli): pin the Finance Explainer pack that varies its motion graphics

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

* feat(cli): media-use generate --type cutout takes a shot out of its background on the plan

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

* chore(cli): pin the Finance Explainer pack without the provisional variety rule

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

* chore(cli): pin the five style packs with variety rules measured on real films

Animated Science gets a worlds-and-boards budget, 3D True Crime a main board and a
brief corner note, 3D Brand caps by measured rate, Finance and Collage set pieces and
more than one look.

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

* docs(skills): media-use names the on-plan cutout and lipsync commands, not the heygen CLI ones

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

* fix(cli): cutout retries dedupe on request_id, uploads carry their real type; style-remix is public

The background-removal route dedupes on the body's request_id and ignores the Idempotency-Key
header, so a retry after a lost answer started a second job: runJob now also sends the key in the
body for such a route. Uploads typed every non-MP4 file as audio, so WebM and MOV inputs were
refused: they now take their type from the extension. Fails without the fix: the new cutout test
in generate.test.ts sees audio/mpeg for WebM and MOV.

style-remix drops metadata.internal and is listed with the other published skills.

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

* chore(cli): keep the comment share of the touched files at main's

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

* docs: count style-remix in the README and CLAUDE.md skill lists

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

* feat(skills): rename style-remix to style-sampling

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 11:07:02 +00:00
Jerrai 3f42dc1c73 feat(cli): diff --offset compares the original at t with yours at t + offset (#7057)
* feat(cli): diff --offset compares the original at t with yours at t + offset

Every per-frame measure (SSIM per frame and per cell, frames.tsv, cuts,
missing content) reads yours offset seconds later, and a project folder is
captured at the shifted times. The window keeps to where both sides have
frames and says so in warnings; an offset with no overlap, or one that is
not a number, is refused with a fix. Sound keeps its own offset reading,
duration is reported as not measured, and the result echoes offset.

* refactor(cli): trim diff offset comments under the file's comment share

* fix(cli): rebase full-length diff offsets and reject overflow

Keep offset streams on a zero-based clock even when every frame is selected. Cover an untrimmed delayed render and reject non-finite offsets before file or project processing.

— Jerrai

* refactor(cli): remove redundant offset filter comment

— Jerrai
2026-11-03 10:48:47 +00:00
WaterrrForever 7ae108005a fix(cli): measure cuts reads a zoom that speeds up as a move, not a cut (#7075)
* fix(cli): measure cuts reads a zoom that speeds up as a move, not a cut

Bug bash (Stripe "pay", 0.9.6): the app window's zoom-in at 0.2 s changes
3, 9, 12, 5 grey levels a frame, and the 12 crossed a cut's level, so
measure cuts listed a cut there and diff failed the rebuild (pass: false at
0.93 similarity) for missing it.

A single-frame cut is now a fast move when the frames either side move too
(30% of its change) and the frame before, zoomed 0.8-1.25x and shifted a few
pixels, comes within 40% of its change of the frame after. A punch-in also
zooms, but out of a still picture, so it stays a cut.

* fix(cli): a zoom is a move only when the picture moves on both sides

Review (hf-review): motion on one side hid a real punch-in out of a still
picture next to a moving shot, and the mirrored punch-out. isMove now needs
both neighbours moving (min, not max). The 33-film check now changes only
Stripe's 0.2 s zoom; league-promo 95.93 s and M1000 5.43 s are cuts again.
2026-11-03 10:20:03 +00:00
WaterrrForever e9de593fe9 fix(cli): measure picks more than 100 frames on ffmpeg 8 (#7071)
* fix(cli): measure picks more than 100 frames on ffmpeg 8

ffmpeg 8 refuses a flat sum of more than 100 terms ("Error while parsing
expression"), and every frame pick in measure, diff and snapshot was one flat
sum of eq(n,k). The ffmpeg HyperFrames downloads is 8.1.2, so measure frames,
diff, face, person, drawn boxes and snapshot all failed past 100 frames.
PostHog: every such cli_error since 0.9.3 came from Windows agents on ffmpeg 8.

sumOf keeps a sum of up to 100 terms flat and nests a longer one in halves.

* fix(cli): sums nest from 51 terms, so ffmpeg 8 takes every pick count

Review (hf-review): 100-term leaves still failed on ffmpeg 8.1.2 once nested,
at 199-201 eq() picks, and snapshot's deeper terms failed at 97-100 times.
ffmpeg 8 limits how deep an expression nests, and a flat sum counts a level
a term. Leaves of 50 pass every count from 1 to 1000 in both shapes, and
1500-5000. Tests decode 199/200/237/401 picks and 97/100/199 snapshot times.
2026-11-03 10:14:37 +00:00
WaterrrForever 91e7f4d48f fix(cli): measure and diff tell an agent what to type after a wrong call (#7072)
The top measure and diff errors since 0.9.4 (PostHog, CLI project) were
agents' calls, not bad videos:

- A flag from another command: --from/--to on ops that take --start/--end
  (extract is the other way round), -o for --out. The unknown-flag error now
  names the flag that means the same here.
- measure sync without --roi stopped at citty's bare "Missing required
  argument"; diff with one video at "Missing required positional argument:
  YOURS". Both now reach their own message with the command to run.
- A Windows path whose backslashes bash dropped (D:videoclip.mp4) was only
  "no file at". The fix line now says to quote it or write it with /.
2026-11-03 09:59:39 +00:00
Miguel Ángel 9ceced05e2 chore: release v0.9.8 (#7077) 2026-11-03 09:15:54 +00:00
James RussoandClaude Opus 5.5 10bc426e32 feat(cli): call HeyGen's v3 media routes through the generated client (#7063)
* feat(cli): call HeyGen's v3 media routes through the generated client

The media-use generate routes (image, video, avatar, voice, music), HeyGen
transcription and the public voice list called fetch by hand. They now go
through the generated cloud client, regenerated with the create and status
methods for those routes.

runJob takes a job route (its path, how it starts, how its status is read)
in place of a path and a poll-path function. Keys, retries, timeouts,
polling and error messages are unchanged. Speech answers in the request and
the API takes no Idempotency-Key there, so it has no status to poll and no
key header is sent.

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

* chore(cli): keep v3.ts comment share at the base

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

* chore(cli): regenerate the cloud client without API description text

The generated client and types now carry names and types only, with no
JSDoc taken from the API spec's summaries and descriptions. The source
contract test checks that no method carries generated description text,
in place of checking the uploadAsset description.

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-11-03 08:59:27 +00:00
Miguel Ángel 3baf81f9a9 fix(cli): reverse on Free runs billing subscribe credited to the run (#7046)
* fix(skills): reverse on Free opens the upgrade page for the person

* docs(skills): reverse on Free opens the upgrade page with a quoted link

* fix(cli): reverse on Free runs billing subscribe credited to the run

* fix(cli): trim the reverse skill and drop a doc comment for lint budgets
2026-11-03 05:46:34 +00:00
James RussoandClaude Opus 5.5 8c799ebd1b chore: release v0.9.7 (#7064)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 05:21:25 +00:00
heygen-rui-botandJames Russo 58a01f1692 chore(codegen): resync cloud client from EF 59dfee8c (#7058)
Co-authored-by: James Russo <james.russo@heygen.com>
2026-11-03 04:55:22 +00:00
James RussoandClaude Opus 5.5 dffc640e85 fix(cli): drop --page-motion-blur from cloud render (#7062)
* fix(cli): drop --page-motion-blur from cloud render

The flag sent page_motion_blur to the hosted render API, which never
accepted that field and rejects unknown fields. Motion blur is set in
the composition with data-motion-blur, and the runtime turns it off on
its own when it cannot render correctly, so the cloud flag is removed
with its request plumbing, test and docs row.

Local render keeps its own --page-motion-blur flag.

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

* chore(ci): allow deleting the cloud render page motion blur test

The deletion guard blocks removed files unless they are listed. The
test file only covered the cloud render --page-motion-blur flag that
this branch removes.

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-11-03 04:21:08 +00:00
James RussoandClaude Opus 5.5 d03bdeae9d fix(cli): prefer OAuth session over HEYGEN_API_KEY (#7051)
* fix(cli): prefer OAuth session over HEYGEN_API_KEY

A signed-in `hyperframes auth login` session now wins over an API key in
the environment, so a paid plan on the login is used even when the shell
also exports HEYGEN_API_KEY.

New order: HEYGEN_ACCESS_TOKEN (host app), the stored login (refreshed
when expired), HEYGEN_API_KEY, HYPERFRAMES_API_KEY, the saved API key.
The env key still comes first when HEYGEN_API_URL or HEYGEN_API_BASE
names a host app's gateway, and takes over for the rest of the process
when the login cannot be refreshed. The media-use audio helper follows
the same order.

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

* fix(cli): fall back to the env key only when HeyGen refuses the refresh

A 503, a network error or an overlapping refresh no longer switches the
process to HEYGEN_API_KEY. The fallback now needs a refused grant or an
expired login with no refresh token. A login another process stored since
is re-read first, and refreshes that overlap in one process share one
request. The media-use helper no longer treats HeyGen's own API base as a
gateway.

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

* fix(cli): keep the login when the refresh reply can't be read

Only a 400/401 from the token endpoint marks the grant as refused and
switches to the env key. A 200 whose body can't be parsed now throws and
leaves the login in place, so the next call refreshes again.

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-11-03 01:52:30 +00:00
Miguel Ángel 81b93cf055 fix(cli): snapshot stops Chrome decoding videos it already replaces with extracted frames (#6949)
* fix(cli): snapshot stops Chrome decoding videos it already replaces with extracted frames

* fix(cli): a held video keeps its intrinsic size in snapshot, as in render

* fix(cli): shorten a comment line in the held-video hints
2026-11-03 01:14:27 +00:00
Miguel Ángel 8a6636efe3 fix(cli): the latest version in _meta is never older than the running CLI (#7049)
* fix(cli): the latest version in _meta is never older than the running CLI

* fix(cli): keep the daily recheck cadence when the cached latest is older than the running CLI
2026-11-03 01:13:02 +00:00
Miguel Ángel de2603e637 fix(cli): auth login --device works without a terminal (#7045) 2026-11-02 23:46:36 +00:00
Jerrai 398ef50624 chore: release v0.9.6 (#7037) 2026-11-02 20:19:33 +00:00
Miguel Ángel 472b750acb fix(cli): cloud export re-encodes media whose bytes differ from its extension (#7033)
* fix(cli): cloud export re-encodes media whose bytes are not the type its extension claims

* test(cli): generated media in the offload tests carries its container header

* fix(cli): an audio-only MP4 named as video is re-encoded as audio

* test(cli): type the header fixture

* test(cli): give the heavy-media dry-run fixture a real mp4 header
2026-11-02 19:14:24 +00:00
JerraiandXuanru Li acd5c30e60 feat(cli): read audio stems through your HeyGen account (#6993)
* feat(cli): audio --read organises the reading by stem

Measures where each stem is heard, leaves the drums' recurring hits to the
music while it plays, names the stem of each remaining effect, writes a
voice-free mix next to the stems, and describes each audible stem and the
whole recording with Gemini.

* feat(cli): audio --read reads stems as vocals, drums, bass and melodic

Piano, guitar and other are mixed into melodic.wav next to the stems; levels,
spans, descriptions, effects and pieces are read per group, and a group heard
for under two seconds or 5% of the recording is left out of the reading.

* feat(cli): audio --read describes the six stems and writes a BGM prompt from them

Stems are read one by one again; a stem heard under two seconds or 5% of the
recording is still left out. Each stem's description gives the times of its
changes and names the effects it hears. The overall and the BGM prompt are
written from those descriptions and the measured spans, not by listening to
the mix again; the BGM prompt orders the arrangement without seconds.

* fix(cli): audio --read writes no BGM prompt for a recording without music

Foley and effects in a rhythm are not music; the reading says so instead of a
prompt that would make a remix generate a track the reference never had.

* fix(cli): audio --read prompts name no example sounds

* fix(cli): describe audio through HeyGen and keep effects measured

* docs(cli): document measured effect events without sound kinds

* fix(cli): clear audio description review checks

Use portable stem path assertions and simplify response validation.
Keep auth-derived URLs out of cache hashes and trim redundant comments.

— Jerrai

---------

Co-authored-by: Xuanru Li <157947275+xuanruli@users.noreply.github.com>
2026-11-02 18:42:05 +00:00
Wenbo ZhuandClaude Opus 5.5 7da583ec69 feat(cli): reverse start stops a Free account when the server blocks it (#7017)
When /v1/hyperframes/reverse/start answers gate "block" for plan "free", `reverse start`
saves the session, then exits non-zero. The error and its `fix` carry the upgrade link that
credits the purchase to this run: the server's `upgrade_url`, else the plans page with
`feature=reverse&rs=<session>`. Pro, unknown plans, `record`, and every error still go on.
The reverse-any-video skill tells the agent to pass that exact link on and stop.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 17:27:31 +00:00
Wenbo ZhuandClaude Opus 5.5 7d3c225207 feat(cli): reverse start records a reverse run; cloud render carries its session (#7016)
* feat(cli): reverse start notes a reverse run with HeyGen and cloud render carries its session

`npx hyperframes reverse start <video> [--dir <project>]` probes the video (the same JSON
as `measure probe`), then, when signed in, calls POST /v1/hyperframes/reverse/start and saves
the returned session id in the project's hyperframes.json. It never stops the run: signed
out, offline, a 404 from a server without the route, or a malformed answer all continue
with the probe and no session. `cloud render` sends `reverse_session_id` only when the
project holds one, which only a successful /reverse/start writes.

`init` now treats a folder holding only hyperframes.json as empty, so `reverse start --dir x`
followed by `init x` works and keeps the session. The reverse-any-video skill opens with
`reverse start` instead of `auth status` + `measure probe`, with a fallback for older CLIs.

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

* chore(cli): keep the comment share of touched files from rising

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

* fix(cli): reverse start keeps unknown-plan sessions, prints the attributed upgrade link, takes only rvs ids

- A `plan: "unknown"` answer is a valid session: saved, `recorded: true`, printed as
  `plan: null`; it never blocks and never falls back to the client-side plan read.
- On Free, `reverse.upgrade_url` is printed: the server's link, else the plans page with
  `feature=reverse&rs=<session>` (the fields checkout reads). The skill passes that exact
  link on instead of `billing subscribe`.
- Session ids must match the render endpoint's pattern (`rvs_<lowercase uuid>`). A saved
  value that does not is ignored: not sent on `cloud render`, and `reverse start` opens a
  fresh session.

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

* docs(skills): name no CLI version for reverse start's fallback

0.9.4 shipped without `reverse start` and skills go live from main before the CLI release,
so the fallback is described as "a CLI without it" instead of a version number.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 16:47:05 +00:00
Miguel Ángel c14d92a227 chore: release v0.9.5 (#7025) 2026-11-02 16:20:52 +00:00
Miguel Ángel 5a07ea2e5f fix(cli): catalog says the registry could not be read instead of listing nothing (#7015) 2026-11-02 14:47:04 +00:00
Jerrai 346f0e49fa feat(producer): report browser-computed reference backgrounds (#7007)
* feat(producer): report browser-computed reference backgrounds

Preserve one initial root/page reference across local, streamed and distributed
render results without guessing from film pixels.

— Jerrai

* fix(producer): preserve plan compatibility and optional inspection

Keep reference metadata outside the v2 manifest hash and read it from the
verified execution-plan artifact. Static planning uses a non-gating page
inspection instead of requiring render-worker capabilities.

— Jerrai

* fix(producer): poll readiness independently of animation frames

Use timed polling while the render clock parks animation frames. Cover readiness
that changes after the first check with a short real-browser regression.

— Jerrai

* fix(producer): budget measured reference metadata runtime growth

Producer adds 2,228 compressed bytes over current main. Tests, fixtures and source
maps are already absent from its dist-only tarball. Allow 7,766 bytes of headroom
above the verified 837,234-byte payload while retaining the unpacked limit.

— Jerrai
2026-11-02 14:42:18 +00:00
Miguel Ángel 34a8d48160 chore: release v0.9.4 (#7018) 2026-11-02 14:33:44 +00:00
Miguel Ángel b23b51f4f0 fix(cli): snapshot fails when an on-screen video frame cannot be read (#7011)
* fix(cli): snapshot reads video frames through any ffprobe and fails on an unreadable one

* fix(cli): snapshot reads video frames through any ffprobe and fails on an unreadable one

* fix(cli): snapshot counts only a failed frame read as unreadable

* fix(cli): snapshot fails when an on-screen video frame cannot be read
2026-11-02 13:48:20 +00:00
Miguel Ángel 8891449401 fix(cli): exit-time telemetry stays silent when the temp folder cannot be written (#6925) 2026-11-02 12:18:46 +00:00
Miguel Ángel f6536e9f5d chore: release v0.9.3 (#7010) 2026-11-02 12:04:35 +00:00
WaterrrForever 8089f0049c feat(skills): soft-launch reverse-any-video, and fix what Wanbi's Pro test found (#7006)
* feat(skills): publish reverse-any-video, render it at high quality, and stop on a stuck shot

From Wanbi's Pro test of reverse-any-video (11-01, checked against 0.9.2):

- A standard install never found the skill: it was internal, and /hyperframes did not route to
  it. It is now an on-demand skill on every catalog surface, and the routing line names it.
- The cloud render in SKILL.md had no --quality high, so the final rendered at standard.
- A re-shoot that stayed pending had no rule; the run waited four hours. people.md now runs the
  command once more after generate's 30-minute stop, then treats the shot as failed.

* feat(cli): generate takes a language for --voice, so a Pro sign-in gets a HeyGen voice

Wanbi's Pro run fell back to Kokoro: --voice needed an id, and the only way to list ids was the
separate heygen CLI and its own login. /v3/voices answers on the HyperFrames sign-in, so:

- --voice <language> picks HeyGen's first public voice in it and names it in the output.
- A missing --voice lists six English voices to pick from instead of a bare error.
- A voice id still goes straight through, with no extra call.

* fix(cli): a voice picked by language stays with its request across re-runs

Rames: `--voice Chinese` re-picked HeyGen's first voice on every run, and the voice is part of the
body and the idempotency key. If the catalog reordered while a job was pending, the same command
could start a second paid job instead of resuming the first.

The pick is now bound to the request (every field, plus the account scope a job bills) in the
project's heygen-jobs.jsonl, or the CLI config dir outside a project, and a re-run reuses it.
Regression: a pending timeout, a reordered catalog, the same command, for voice and avatar; the
second POST keeps the voice, body and key.

* fix(cli): a voice pick waits for a known account instead of binding to none

Rames: when /v3/users/me failed, senderScope() was null and the pick was bound to an empty
scope; once the account came back, the same command missed that binding and could pick another
voice and paid key. pickVoice now stops before picking or posting while the account is unknown,
and never reads or writes a blank-account binding.

Regressions, both directions: unknown then known refuses with no POST, then picks once; known
then unknown refuses the re-run with no second POST, then resumes with the same body and key.
Also README: a non-interactive install gets all 8 skills, not 7.
2026-11-02 11:48:55 +00:00
Miguel ÁngelandHuntsDesk c54f84859d fix(studio-server): long media clips no longer leave the host unanswered (#7002)
* fix(studio-server): more than six clips on one media file no longer starve check and preview of connections

Every file server answered `Range: bytes=N-` with the rest of the file. A
media element reads that until its buffer is full, then stops reading but
keeps the response open, so each <video> held one of Chrome's six HTTP/1.1
connections to the host. With seven or more <video> clips on the server's
host, every other request queued behind them and `hyperframes check`
stalled at 0% CPU. A long recording cut into trimmed segments, each its own
<video> on the same file, is enough.

An open-ended range of audio or video now gets at most 4 MiB
(OPEN_MEDIA_RANGE_BYTES), as a normal 206 with an exact Content-Range. The
element asks for the next range as it plays or seeks. Bounded and suffix
ranges, and files that aren't media, are served as before. The helper lives
in studio-server; its preview route and the CLI's static project server and
composition server use it.

Fixes #6029

Claude-Session: https://claude.ai/code/session_014aw1z3VrTNenka3LGDBBLa

* fix(studio-server): carry the range cap's reason in names and tests, not comments

The comment ratchet doesn't let a file's comment share rise: mediaRange.ts
was 48% comments against the package's 7%, and staticProjectServer.ts gained
a line. The cap is now MAX_OPEN_MEDIA_RANGE_BYTES, and the why and the
repro stay in the three tests and #6029.

Claude-Session: https://claude.ai/code/session_014aw1z3VrTNenka3LGDBBLa

* fix(producer): the render file server bounds open-ended media ranges too

parseRangeHeader takes the response's content type and caps an open-ended
`bytes=N-` on audio or video with openRangeEnd, like the CLI and Studio
servers. The producer imports it from a new `media-range` subpath of
@hyperframes/studio-server, as it does `encoder-options`, so a render
doesn't load the rest of the package.

Claude-Session: https://claude.ai/code/session_01DW4V8HZZx5JUgMffb3juVV

* test(cli): eight clips on one file no longer leave the host unanswered

A real Chromium page buffers eight long video clips of one file from the project server and then asks the same host for another file; with open-ended ranges unbounded the request stays unanswered, with the bounded piece it is answered at once.

* docs(producer): range comments name the open-ended form in lowercase

* docs(cli): the range test's comment says what holds now

---------

Co-authored-by: HuntsDesk <hunter@talloak.com>
2026-11-02 11:03:55 +00:00
WaterrrForever 618c486734 fix(cli): measure and diff report why they failed, and reverse reports its runs (#6997)
* fix(cli): measure and diff report why they failed, and reverse reports its runs

Since launch, 97 people saw a bare "Command failed" from measure: runMeasure
and diff called failCommand() without the error, so telemetry kept only the
wrapper. 59 agents ran `measure <file>` with no op and got no hint. Reverse
runs had no skill tag, so nobody could count how many finished.

- runMeasure and diff pass the error to failCommand.
- An unknown word that is an existing file names the commands to put first.
- references/start.md sends skill_invoked and skill_completed beacons.

* fix(cli): the file hint stays out of the root command list

Jerrai: `hyperframes index.html` would list every top-level command. fileHint moves to
didYouMean.ts, answers only inside a command group, and has tests for the root, a missing
file and a group with no commands.
2026-11-02 10:03:08 +00:00
Miguel Ángel 5e50ac1c47 chore: release v0.9.2 (#6994)
* chore: release v0.9.2

* chore: release v0.9.2
2026-11-02 08:42:46 +00:00
James RussoandClaude Opus 5.5 870569a431 chore: release v0.9.1 (#6987)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-02 07:14:25 +00:00
James RussoandClaude Opus 5.5 f1391156e0 chore: release v0.9.0 (#6980)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-02 05:14:22 +00:00
WaterrrForever b1316e61d1 fix(cli): diff stops counting a fast move as an extra cut (#6978)
A regenerated shot never lines up with a whip frame by frame, so diff listed every fast move.

A jump now counts only above the original's own motion around it.

fails without the fix: reads a change no stronger than the original's motion as the same fast move
2026-11-02 04:50:16 +00:00
WaterrrForever 99223d993c fix(cli): diff warns when yours runs at another frame rate (#6976)
A root without data-fps on a 24 fps film rendered at 30 fps, and nothing said so.

fails without the fix: warns about a render at another frame rate
2026-11-02 04:09:30 +00:00
Miguel Ángel f0b2dd0cdb chore: release v0.8.231 (#6971) 2026-11-02 03:34:08 +00:00
Miguel Ángel c06427b063 test(cli): run the real npx shim check only in its own CI job (#6969)
* test(cli): the npx command test builds the command instead of running a real npx

* test(cli): run the real npx shim check only in its own CI job
2026-11-02 02:18:03 +00:00
Miguel Ángel f8309b356e fix(cli): media-treatment reads a relative --grading file from the project folder (#6964) 2026-11-02 01:47:06 +00:00
Miguel Ángel 7c5c1ce849 fix(cli): the browser install hint names only a Chrome that exists (#6954) 2026-11-01 23:54:29 +00:00
Miguel Ángel fb2c28e8aa chore: release v0.8.230 (#6962) 2026-11-01 23:52:11 +00:00
Miguel Ángel 53c93ba68e fix(cli): snapshot shoots a frame again when Chrome drops the screenshot mid-paint (#6941)
* fix(cli): snapshot shoots a frame again when Chrome drops the screenshot mid-paint

* fix(cli): keep the first screenshot error when the retry fails differently
2026-11-01 23:19:16 +00:00
Miguel Ángel 2bce65ee1b fix(cli): add the audio and transcribe topics to hyperframes docs (#6960) 2026-11-01 23:16:56 +00:00
Miguel Ángel de6ec3811e fix: cache paths follow HYPERFRAMES_CACHE_DIR (#6716)
* fix: cache paths follow HYPERFRAMES_CACHE_DIR

Every place HyperFrames keeps downloaded or built files now takes its
folder from one helper, hyperframesCacheDir() in @hyperframes/core. The
default stays ~/.cache/hyperframes; HYPERFRAMES_CACHE_DIR moves it.

* fix: register the cache-dir subpath for bun and node, and build inspector from core source

* test: the cache-dir override test uses a folder that is absolute on every platform

* fix: the opencv cache follows HYPERFRAMES_CACHE_DIR

* fix(cli): npm installs run in their staging dir, so no cache path reaches a command line

* fix(cli): whisper.cpp is cloned inside its build dir, so no cache path is a git argument

* test(cli): the whisper clone test finds no system whisper on Windows either
2026-11-01 22:44:11 +00:00
Miguel Ángel 465128d002 fix(cli): media-treatment says which media the file has when the selector matches none (#6958) 2026-11-01 22:22:18 +00:00
Miguel Ángel 5c5794287b fix(cli): say a font or image URL is a download, not a page, when capture is given one (#6952)
* fix(cli): say a font or image URL is a download, not a page, when capture is given one

* fix(cli): word the capture download hint as a likely cause, not a fact
2026-11-01 21:52:04 +00:00