109 Commits
Author SHA1 Message Date
Miguel Ángel a373071261 feat(cli): beats analyses an audio or video file given directly (#6812)
* feat(cli): beats analyses an audio or video file given directly

* docs(skills): the beats reference says a file argument is analysed directly
2026-10-30 10:09:07 +00:00
James Russo 3e462f4277 feat(cli): use dedicated HyperFrames OAuth clients (#6687)
* feat(cli): use dedicated HyperFrames OAuth clients

* docs(cli): shorten credential store contract comment

* fix(cli): respect Windows modes in OAuth media test

* fix(cli): keep media workflows on HyperFrames OAuth

* test(cli): scope billing status assertions to wallet rows

* test(cli): align telemetry fixtures and CI auth inputs
2026-10-29 21:25:20 +00:00
Miguel Ángel 5d437d5eec docs(cli): say which audio probes run once per file (#6731) 2026-10-29 08:10:51 +00:00
Miguel Ángel fa97f9d4b7 docs(cli): list check's audio findings with severity, trigger and fix (#6730) 2026-10-29 07:41:09 +00:00
James RussoandClaude Opus 5.5 1c3fcf4d23 feat(telemetry): identify signed-in CLI users by their HyperFrames user id, and say signed-in usage is not anonymous (#6703)
* docs(telemetry): say signed-in usage is linked to your account, not anonymous

After hyperframes auth login the CLI sends a PostHog $identify with the
account email (username as fallback) and merges the install's earlier
anonymous usage; media-use does the same when it finds a signed-in
account. Several places still called all telemetry anonymous. Say it is
anonymous until you sign in, in the CLI reference (media-use, --skill,
feedback, events, telemetry), the hyperframes-cli skill references, and
the CLI help and notice strings.

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

* feat(telemetry): identify signed-in CLI users by their HyperFrames user id

The CLI and media-use identified a signed-in install by account email, so
CLI usage landed on a different PostHog person than the same account in
the HyperFrames web app, which keys on toUUID(username). Identify by that
same sha256-derived id instead, and $set email plus heygen_username on the
person. heygen_username is the cross-project join column for the Snowflake
event table (HeyGen's own project stores it as `name`). An account with no
username still falls back to the lowercased email.

Notices and docs now say usage is keyed on an id derived from the username
with email and username stored on it.

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

* chore(telemetry): trim comments to the package's comment share

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

* feat(telemetry): put heygen_username on every event while signed in

The Snowflake event sync may not carry PostHog person properties, so a
$set alone does not let an event row join across projects. The CLI now
adds the signed-in HeyGen username (raw, from ~/.heygen/credentials) to
every event and drops it once the credentials hold no user; media-use
does the same on each event it sends.

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

* ci: count auth/paths.ts as an edit-accuracy bench input

Telemetry now imports it to read the signed-in username.

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

* fix(telemetry): stat and read the credentials through one file handle

CodeQL flagged the stat-then-read as a file system race.

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

* fix(telemetry): key signed-in events on the account id; fix stale anonymity copy

Genesis review on #6703:
- telemetry --help listed 'Any personally identifiable information' as
  never collected, and media-use's meta.md still said anonymous.
- Installs already identified by email under an older CLI never merge
  into the new person, so send signed-in events with distinct_id = the
  account id (back to the install id after logout), in the CLI and in
  media-use, and stop claiming earlier usage always merges.
- A user block with no credential no longer counts as signed in.
- A UUID-shaped username passes through unhashed, as on the web.

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-29 02:57:48 +00:00
Miguel Ángel 2a0fa7f4de fix(cli): check fails a full-frame element that covers every other clip, naming it (#6572)
* fix(cli): check fails a full-frame element that covers every other clip, naming it

* test(cli): shorten the cover scene helper's comment

* chore(skills): refresh the manifest for the check reference

* fix(cli): full-frame b-roll over a backdrop is not a covered canvas
2026-10-27 17:38:21 +00:00
Miguel Ángel 5a92fe7e5e fix(cli): beats given a media file points to hyperframes audio instead of a folder error (#6544)
* fix(cli): beats given a media file points to hyperframes audio instead of a folder error

* fix(cli): beats names the folder for a composition file and syncs the skills manifest
2026-10-27 10:49:26 +00:00
Xuanru LiandJerrai 53d3caeac5 feat(cli): capture can route its traffic through an opt-in upstream proxy (#6499)
* feat(cli): capture can route its traffic through an opt-in upstream proxy

HYPERFRAMES_CAPTURE_PROXY=http://host:port sends the capture browser proxy's
forwarded requests and CONNECT tunnels, and every publicRequest download,
to that proxy by hostname instead of dialing a checked public IPv4. Unset,
behaviour is unchanged.

* fix(cli): keep capture comment share flat and close the new CodeQL findings

Test fixtures record what they receive instead of echoing request data, and
capture --video strips line breaks from a failed download's message before
logging it.

* fix(cli): proxied HTTP downloads send no URL fragment, and a malformed proxy credential is refused

The absolute-form request to the upstream used the URL's href, so a fragment such as
sprite.svg#icon went on the request line, which the pinned path never sends and strict proxies
refuse. A malformed percent-escape in the proxy credentials threw a bare URIError instead of the
usual "not a valid proxy URL" error. The test servers label their echoes text/plain.

* fix(cli): strip line breaks from capture --video errors in the form CodeQL recognizes

* fix(cli): capture --video logs errors through a recognized newline sanitizer

---------

Co-authored-by: Jerrai <jerrai@heygen.com>
2026-10-27 02:52:52 +00:00
Miguel Ángel 54d0af57eb feat(engine): render sets a keyframe interval and a peak bitrate cap (#6444)
* feat(engine): encoders cap peak bitrate and place keyframes on a set interval

* style(engine): shorten the rate-cap comment

* style(engine): drop the doc lines the comment ratchet flagged

* feat(producer): mp4 renders honour a keyframe interval and a peak bitrate cap on every encoder path

* style(producer): shorten the delivery encoder file headers

* style(producer): drop a comment line from the segment manifest

* style(producer): shorten the integration test header

* test: delivery encoder tests follow the ffprobe argv contract and run in the integration lane

* feat: the render request, server and Lambda plan carry the keyframe interval and peak bitrate cap

* fix(studio): the Studio render route passes the keyframe interval and bitrate cap to the encoder

* chore(studio-server): drop a comment the helper's name already says

* feat(cli): render and lambda render take --keyframe-interval, --max-bitrate and --buffer-size
2026-10-27 00:29:06 +00:00
Xuanru Li 257bf285ff feat(cli): skipContrastInMotion moves to HF_TOOL_CONTEXT check-review (#6400)
* feat(cli): skipContrastInMotion moves to HF_TOOL_CONTEXT check-review

The --skip-contrast-in-motion flag and HYPERFRAMES_CHECK_SKIP_CONTRAST_IN_MOTION
env give way to a check-review capability in HF_TOOL_CONTEXT, so only a harness
turns it on. The skill text and manifest go back to main.

* fix(cli): satisfy comment ratchet for check capability
2026-10-26 07:42:50 +00:00
Xuanru Li afdad4ea38 feat(cli): opt-in check flag that leaves out contrast measured mid-animation (#6396)
* feat(cli): opt-in check flag that leaves out contrast measured mid-animation

`hyperframes check --skip-contrast-in-motion`, or
HYPERFRAMES_CHECK_SKIP_CONTRAST_IN_MOTION=1, leaves out a contrast failure
measured while a GSAP tween on the text or an ancestor is running, or while
the text's cumulative opacity is below 1. Repeating tweens and tweens of 4 s
or longer (camera drifts) do not count as motion. Text no GSAP tween targets
is reported as before. With neither set, check is unchanged.

The motion state is read at the same contrast sample, with no extra seek or
screenshot.

* fix(cli): read contrast motion on current GSAP clocks

* fix(cli): keep infinite timeline motion ambient
2026-10-26 06:22:46 +00:00
Miguel Ángel a11280eef0 perf(cli): lambda deploy warms the video function so the first render does not wait for its image (#6376)
* perf(cli): lambda deploy warms the video function so the first render does not wait for its image

A freshly deployed container-image function loads its image on first use, which added about 12 s to the first render's plan on some deploys. Deploy now invokes the function's warm action once after the stack is up (default on, --no-warm skips it). A failed warm-up prints a warning and the deploy still succeeds.

* chore(cli): move the deploy warm-up to its own file, regenerate the skills manifest

Regenerates skills-manifest.json for the lambda reference change, keeps runDeploy under the complexity gate by pulling the warm step into a helper, and leaves sam.ts untouched.

* fix(cli): the deploy warm-up asks the aws CLI for JSON output whatever the profile sets

A profile configured for text or yaml output made the reply unparseable, which printed a spurious warm-up warning.

* refactor(cli): split the reserved-concurrency notice and warm-up gate out of runDeploy
2026-10-26 05:32:53 +00:00
Miguel Ángel 0d104e6fca fix(cli): init never touches installed skills and no command removes one (#6168)
* fix(cli): init and skills update only touch HyperFrames skills; --skip-skills works

* fix(cli): init never touches installed skills and no command removes one

* fix(cli): shorten the init skills comment

* fix(cli): shorten the init skills comment

* fix(cli): the stale-skills notice reaches agents that run without a terminal

* test(cli): a run without a terminal now checks skills in the background

* fix(cli): the stale-skills notice also prints on --json runs
2026-10-24 04:08:29 +00:00
Jerrai 7a34d6fbe4 docs: align render, fps and transcribe docs with the CLI (#6166)
* docs: align render, fps and transcribe docs with the CLI

- docs/guides/rendering.mdx: default render quality is `looks` (CRF 16),
  not `standard`.
- docs/packages/cli.mdx, render --help (render.ts): default --output is the
  timestamped `renders/<project>_<YYYY-MM-DD>_<HH-MM-SS>.<ext>`.
- skills/hyperframes-cli/references/preview-render.md: local --fps accepts
  1-240 or a rational and defaults to the root data-fps, else 30; only
  lambda and cloudrun are limited to 24, 30, 60.
- skills/hyperframes-cli/references/lint-validate-inspect.md: snapshot
  --range is documented as START,END like every other reference.
- skills/media-use/references/audio.md, skills/media-use/audio/references/
  transcribe.md, skills/hyperframes/references/captions.md: name the entry
  point for each transcription default (transcribe.mjs prefers Parakeet;
  `hyperframes transcribe` uses Parakeet when installed, else the small.en
  whisper model).
- transcribe --model help text and docs/packages/cli.mdx: list `small` and
  `medium`, which the CLI already accepts.
- skills-manifest.json: regenerated hashes for the three skills touched.

— Jerrai

* docs: lambda and cloud run also accept 25 fps

Distributed renders accept 24, 25, 30 and 60 fps (DISTRIBUTED_FPS in
packages/core/src/distributedFps.ts).

- skills/hyperframes-cli/references/preview-render.md: the --fps note
  lists 24, 25, 30, 60 for lambda and cloudrun.
- skills/hyperframes-cli/references/lambda.md, cloudrun.md: --fps lists
  include 25.
- packages/cli/src/docs/rendering.md (`hyperframes docs rendering`): --fps
  said 24, 30 or 60 and --quality defaulted to standard; local render takes
  1-240 or a rational, default root data-fps else 30, and the default
  quality is looks.
- skills-manifest.json: regenerated hyperframes-cli hash.

— Jerrai

* chore(skills): regenerate skills manifest after formatting

The format hook rewrote skill markdown after the manifest hook had hashed
it, leaving the hyperframes-cli hash stale.

— Jerrai
2026-10-24 00:29:56 +00:00
Jerrai d5526bd480 docs(skills): remove duplicated sections in skill references (#6164)
- skills/hyperframes-cli/references/upgrade-info-misc.md: the "Remaining
  harness usage" section (heading plus three paragraphs) appeared twice in
  a row; removed the second, byte-identical copy (8 lines).
- skills-manifest.json: regenerated the hyperframes-cli content hash, as the
  manifest check requires after a skill file changes.

No wording changed.

— Jerrai
2026-10-23 23:52:28 +00:00
WaterrrForeverandClaude Opus 5.5 688229314f feat(skills)!: publish seven knowledge skills aligned with Studio and retire the workflow skills (#5651)
* refactor(skills): fold six domain skills into hyperframes and media-use guides

hyperframes-core, -animation, -keyframes, -creative and -studio move to
skills/hyperframes/{core,animation,keyframes,creative,studio}/, and
hyperframes-audio moves to skills/media-use/mix/. Each moved SKILL.md becomes
a frontmatter-free GUIDE.md so installers that scan recursively for SKILL.md
no longer see them as skills; the published list goes from 21 to 15.

Relative links, code paths and skill-name mentions are rewritten to the new
locations, the catalog surfaces, marketplace core-skills list, fallback core
set, module-copy targets and skills-manifest.json follow, and
`hyperframes skills update` now removes the retired skills (RETIRED_SKILLS)
when they are still installed.

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

* feat(skills): slim the core entries and give media-use a HeyGen and a free path

The four entries every run opens are rewritten to what an agent cannot infer:
hyperframes 21.8 KB to 7.7 KB, hyperframes-cli 24.8 KB to 6.9 KB,
hyperframes-registry 9.9 KB to 4.3 KB, media-use 9.7 KB to 4.9 KB. Detail moved
whole into references (routing close calls and creator edits, CLI pin upgrades,
catalog search tiers, CLI conventions and feedback reports).

- hyperframes: state table, routing, the render contract, a terminal work loop
  (check, snapshot, preview before render), the desktop-app hand-off, and a
  table of the folded guides.
- media-use: one table of HeyGen versus free local tools per need; HeyGen
  sign-in, credits and the CLI's video-agent, avatar, clone, lipsync, translate
  and clipping commands; every free path works with no account.
- scripts/check-core-skills.mjs holds entries and descriptions to budget and
  checks every taught `npx hyperframes` command and path; runs in lint.
- Core entries are exempt from the formatter: its table padding cost ~1.5 KB
  per entry on every run.
- Content tests follow the text to its new home.

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

* fix(skills): plugin runs skip skills update; media-use explains HeyGen sign-in and TTS setup

The smoke eval showed a presenter request never reaching media-use and the
free voiceover failing on a missing kokoro-onnx; plugin runs also ran the
skills update the plugin rules forbid.

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

* chore(skills): drop a committed Python bytecode file and ignore bytecode

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

* feat(skills): align the entry with the Studio skills and keep the workflows' measured facts

The entry drops routing and the intent interview and carries the contract, the
editable-project rules and the work loop. Studio's format, runtimes, motion,
look and captions references come over for terminal use, frame presets move to
assets/, media-use gains Studio's mixing and local-command references, and
film.md and overlays.md keep what the workflow skills measured.

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

* feat(skills)!: retire the workflow skills and folded guides; publish seven knowledge skills

The skill pack now publishes exactly seven skills - hyperframes,
hyperframes-cli, hyperframes-registry, media-use, figma, slideshow and
remotion-to-hyperframes - carrying knowledge, not process. The eight
workflow skills, the folded domain guides and the routing/interview
references are deleted; their measured facts already live in the
hyperframes references (format, runtimes, motion, look, captions, film,
overlays) and media-use's mixing reference.

- bake-basemap.mjs and locate.mjs move to skills/hyperframes/scripts/
  (bake-basemap gains --help); extract-audio-data.py moves to
  media-use/audio/scripts/ for the caption motion reference.
- skills update: the eight workflows join RETIRED_SKILLS so existing
  installs prune them (by lock attribution only, since their names are
  generic); naming a retired skill reports where its knowledge went and
  succeeds instead of failing as unknown.
- Capture prompts point at the hyperframes skill's references/film.md;
  the live-map warning names the new bake-basemap path.
- Content tests that pinned knowledge are retargeted to the kept
  references; tests of deleted workflows, scripts and process go.
- Catalog surfaces, templates and docs describe the seven skills.

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

* fix(skills): resolve the local.md captions link and allow capture's output files in citations

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

* fix(skills): regenerate the skills manifest from tracked files only

The committed media-use hash included an ignored __pycache__ bytecode file present
in the local checkout, so CI's clean checkout hashed differently.

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

* fix(docs): restore generated catalog pages and docs navigation to main

Catalog PRs commit item sources only; CI regenerates the pages from the edited
registry sources. docs/docs.json is catalog navigation, so its Workflows group
rename is left for a non-catalog PR.

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

* build(cli): raise the CLI size budget for the skill references it bundles

The CLI bundles skills/hyperframes, which now carries the folded domain guides and
frame presets (155 KB to 1.08 MB in git). Budgets are the CI-measured size plus 5%:
packed 7526634, unpacked 22593213.

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

* test: keep repo-sweep guards meaningful after the workflow skills left

The last shell ffprobe caller and most root index.html examples lived in retired
skills. The shell detector is now pinned on a literal command line, and the
structure-rule sweep needs more than 5 roots (11 remain) rather than 30.

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

* feat(skills): slim figma, slideshow and remotion to the Studio shape; restore the storyboard board

slideshow 33.5 KB to 4.9, figma 18.2 to 6.2, remotion-to-hyperframes 11.0 to
4.9, each keeping the facts only it holds (the figma motion helpers, verify gate,
storyboard decoding and usage beacons; present and hand-off; the Remotion lint,
SSIM check and API map). The board page format from the storyboard recipe comes
back as hyperframes/references/storyboard.md: the desktop app's Storyboard tab
reads boards/storyboard.html by its frame, title and time classes. The entry and
the init template now say to snapshot the moments an edit changed before
replying, which the terminal eval found skipped in 22 of 38 runs.

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

* fix(skills): manifest without local bytecode; Studio's edit prompt names kept files

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

* fix(skills): render when the person asks for the file or for no stops, not only after approval

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

* fix(skills): keep the voiceover carve in media-use; presets stage their own fonts

Review follow-ups on #5651:
- carve.mjs and its tests move to skills/media-use/audio/scripts; the audio
  docs, mixing.md and two Studio comments point there.
- code-editorial's FRAME.md says to copy its bundled WOFF2s and add the
  @font-face blocks, instead of promising the retired build-frame.mjs.
- media-use states the host rule before the HeyGen sign-in steps.
- storyboard-format marks transition_in as a note the agent builds itself.
- Two stale citations (creator-editing-recipes.md, sub-compositions.md).

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

* chore(skills): regenerate the manifest without local bytecode

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

* fix(skills): the CLI render step follows step 4's rule, not approval alone

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

* fix(ci): run the core-skills check from lint again after the main merge

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

* feat(skills): films that tell a story start from three storylines; maps use real imagery

Opus 5.5 arm D read motion.md and applied it, but its launch film was a
feature list (pain, three feature cards, proof, logo): film.md left story
to the model. And the map case never opened film.md, so it drew Natural
Earth outlines instead of baking satellite tiles.

- references/story.md: the generic half of Studio's moment-film story and
  craft (one thing, three storylines with world and device, the hook,
  beats, worlds, copy, brand, tells of a generated film). The person picks
  a storyline, or the agent takes its recommendation when asked for the
  file or for no stops.
- The entry's work loop names the storyline step for films over ~15 s; the
  references table routes stories to story.md and maps to film.md.
- film.md points at story.md and gives maps and real places a section.

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

* fix(skills): story.md follows the entry: no voiceover unless asked

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

* fix(skills): bake-basemap starts from a globe and stops waiting out its idle timeout

The Opus 5.5 map run spent 13 of its 38 minutes on parallel bakes that
stalled and 15 more recording 300 frames, after rewriting the script because
it could only start on a flat map.

- PROJECTION=globe with a seeded starfield and atmosphere, and FROM/PAN to
  turn the globe to CENTER before the dive.
- Each frame polls for loaded tiles instead of waiting for an "idle" event
  that had often already fired: 30 frames went from 198-219 s to 10-13 s
  locally with byte-identical frames.
- Progress prints seconds a frame and minutes left; film.md shows the globe
  call and says to run one bake at a time.

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

* fix(skills): render in the foreground; wait on a detached render's log, never pgrep -f

Both Opus 5.5 explainer runs started a detached render, then waited with
`until ! pgrep -f "hyperframes render"`, which matches its own loop: each
render took 88-117 s and the wait sat for the tool's full 10 minutes.

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

* feat(skills): route each kind of film; storylines carry look and sound; add review and sound

The entry routes by request (launch, explainer, music, data, vertical, 3D,
character) to a self-contained file under references/types/, and a film
over ~15 s now gets music and sounds on its visible actions unless the
person asked for silence. Each storyline names its look and its sound, so
picking one picks both; STORYBOARD.md frames carry `reads` and `sound`.

review.md is the whole-film pass: the check warnings, the review sheets,
seven questions to look for, P0/P1/P2 notes and REVIEW.md. motion.md gains
eases by role, six title entrances, a reading-time rule and nine measured
transitions; look.md a design plan before the first scene, with presets
kept for decks and named picks. story.md adds the second default that
generated design falls into, with what to do instead.

The blank template and format.md no longer teach the fade-and-slide-up
entrance on a dark canvas.

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

* feat(cli): check warns on unread lines, dead stretches, small type, empty frame 0 and silence

A coding agent cannot watch its film, so check now measures what a viewer
notices over time. A new `craft` section holds warnings only (exit 0
unless --strict), sampled on the dense 8 fps grid the overlap pass
already seeks, skipped for --range checks:

- line_unread: a reading-size line (>= 30 px tall at 1080) on screen
  under 0.4 s for 1-2 words, else under 3/4 of 0.5 s + 0.3 s a word;
  the film's last line needs 2 s. Short lines are re-measured between
  samples to ~0.01 s before judging. Captions-track and
  data-layout-ignore text are exempt.
- dead_stretch: more than 3 s where the keepsMoving liveness signature
  does not change, outside the final 3 s and any data-hold element;
  quiet when sweep_static fires or a whole-composition keepsMoving
  assertion owns the limit.
- text_below_floor: text under 2.6% of the short side (28 px on 1080)
  held 0.5 s, one finding per file listing every element.
- first_frame_empty: frame 0 paints only the background.
- film_silent: over 15 s with no unmuted audio or audible video.

Each message names the fix and the skill reference to read. keepsMoving
now also leaves the film's last 3 s (a still end card) out of its
static runs, so the two agree.

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

* feat(cli): snapshot --review captures a beat sheet, seam strips and a phone sheet

snapshot --review picks the frames that show a film over time instead of
evenly spaced ones, in the same single browser session:

- review-beats.jpg: one settled frame per scene at its start + 0.3 s,
  plus one per timed data-beat="name" element, labelled time and id.
  Scenes are the composition's top-level timed clips and sub-composition
  hosts, read like `timeline` reads rows (captions and audio excluded)
  and timed by the runtime's start resolver over the live page.
- review-seam-NN.jpg: frames at -0.2, -0.1, 0, +0.1, +0.2 s around
  every cut (each scene start, and any scene end no scene starts at).
- review-phone.jpg: the beat frames at 360 px wide.

--composition scopes the review to one sub-composition; with fewer than
two scenes the beats spread evenly and a note says so. snapshot also
gains --json: one envelope with every frame's path and time and, under
--review, the scenes, beats and seams behind the sheets; progress moves
to stderr.

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

* fix(cli): craft warnings stay out of --strict; a hold gets a real next action, not a caret

Craft findings (unread lines, dead stretches, small type, an empty first
frame, silence) are judgment calls a film may break on purpose, so
--strict keeps gating defects only. The check reference no longer
suggests a blinking caret to keep a still frame moving.

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

* fix(cli): review spreads beats when every scene starts together; map credits skip the type floor

A map film whose basemap and overlay both start at 0 s got one beat
frame; the even spread now keys on distinct scene starts. film.md tells
agents to mark the imagery credit data-layout-ignore and back it, since
the new type floor flagged it on the first real run.

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

* fix(cli): review frames each scene at its middle too, not only 0.3 s in

On the first real explainer, 0.3 s into a scene showed a bare colour
field before its title entered. Each scene longer than about a second
and a half now adds a frame at its middle, so the sheet shows what the
scene builds.

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

* feat(skills): a film is built from a numeric SPEC.md, with defaults banned by name and a look test

Studied in full: flxrnc's Motion Lab (vague vs directed prompt), 0xMovez's
course, EianLu's riso skill, agentchengfeng's style samples and the two
Opus 5.5 guides. Their common point: adjectives are where the default look
lives, so the agent now writes SPEC.md before any scene (GOAL, OUTPUT,
TIME, LOOK, MOTION, SHOTS, BANNED, QA), with a number for every adjective.

spec.md bans the defaults by name, unless the brand or reference uses
them (a dark void with small things floating, glow and particles, the
cream-serif-mono-label look, fade-and-slide-up, corner brackets), and
grows that list after the first render. Each storyline gets a 3 s test of
its hero shot before the pick; a look is written as the rules of one
medium. Composition numbers: the hero fills 40% of the frame, one hero
move per shot, the shot's information in within 2.5 s then a held poster.

motion.md adds springs by damping ratio, shorter exits, overlap, stagger
and the beat grid; review.md reviews as a harsh director and grows BANNED;
vertical.md takes the riso skill's measured safe band; explainer.md the
shapes of information.

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

* fix(skills): story before look; every object reads as itself; posters only for info cards

The first spec-driven C02 swapped the dark default for a flat Swiss
poster, and the story went with it: two black bars nobody read as mirrors,
slogans instead of cause and effect, a storyline picked for its picture.

The spec now serves the story: a storyline is picked for the story a
stranger would follow, the look test asks first whether a stranger
understands what they see, and SPEC.md gains an OBJECTS line giving each
thing the material and details that make it read without a label. The
2.5 s held-poster rule is limited to information cards; in a story film
every shot causes the next. Explainers start from a person or situation
the viewer knows. Review names every object as a stranger would and
treats one that needs explaining as a P0.

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

* fix(skills): storylines are three films in words, each with a device and a form

The three storylines are pitched as text and the person picks from them;
nothing is built for a storyline before the pick, so the 3 s hero-shot
look test is gone. Ideas pair a device with a form, five or more first,
keeping the three that differ most, and the one stop states the rest in
an assumption line that names every paid item beside its free option.

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

* ci: list main's new embedded-captions hf-cli test among the retired workflow files

The merge with main removed it with the rest of the retired skill, and the
deletion guard rejects any removal it has not been told about.

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

* fix(core): keep the audio preset comment within core's size budget

The comment's new citation to media-use's mixing reference made the published
package 14 bytes larger than its budget, which sits at main's exact size.

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

* fix(cli): craft keeps its own 8 fps grid; comments back within the checks

Review on #5651 found that the merge moved craft onto the overlap pass's
times, which main caps at 180, so a brief line in a long film fell between
samples and line_unread missed it. Craft now builds its own grid at 8 fps up to
600 samples, as before the merge, and a 60 s film with a line shown for 0.2 s
pins it.

The Comments check passes again: REVIEW.md and STORYLINES.md join the files a
skill writes into a project, the comment lines this branch added come back
under each file's share at the merge-base, and the audio preset comment drops
a word the check reads as history.

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-21 19:19:31 +00:00
Miguel Ángel cddb34feac perf(cli): cloud render downloads the finished video over parallel connections (#5864)
* perf(cli): cloud render checks render status every 2 seconds instead of 10

A finished render was noticed up to 10 s late. Polling every 2 s cuts that
wait to at most 2 s and stays well under the status endpoint's rate limit.
`--poll-interval` still overrides it.

* perf(cli): cloud render downloads the finished video over parallel connections

The first request asks for the first 8 MB. When the server answers 206 with
the full size, the rest of the file is fetched in up to 7 more ranged
requests at once and each part is written at its offset into the staged
file. A server that ignores Range (200), a small file, or an empty file
is still fetched in one request. A failed part cancels the others and the
existing output is kept, as before.
2026-10-19 00:12:57 +00:00
WaterrrForeverandClaude Opus 5.5 cea8aa8a7d feat(cli): judge text behind a transparent video by its decoded alpha in check (#5657)
* feat(cli): judge text behind a transparent video by its decoded alpha in check

The layout audit treated every <video> as opaque over its whole box, so a
caption between footage and a remove-background cutout always failed
text_occluded and needed data-layout-allow-occlusion, which also hid a word
the subject's head fully covered.

check now draws the video's current (seeked) frame into one reused,
downscaled scratch canvas, once per sample and only for a video a text probe
lands under. A fully opaque frame keeps today's behaviour. A frame with
transparency is judged per rendered word against its alpha: partial cover is
an info finding carrying the most covered word's share, and a word 80% hidden
or two neighbouring words each half hidden is an error. A frame that cannot
be read falls back to opaque with a video_alpha_unread info note.

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

* test(cli): serve the video-alpha fixtures from memory, not request paths

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

* fix(cli): check finds words under narrow, mirrored or backed cutouts

Review follow-ups on #5657:
- A matte the probe walk passes over, even at clear-alpha points, now triggers
  the per-word check, so a feature between two probe columns (an arm, a mic
  stand) still fails the word it hides.
- Mirrored videos and images map viewport points through the flip; a rotated,
  skewed or 3D-transformed video falls back to opaque with video_alpha_unread.
- A video with an opaque CSS background keeps its whole box occluding.
- cli.mdx lists every unread cause and why a fully transparent frame is one.

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-15 18:53:16 +00:00
Xuanru Li 1544b519a9 feat(cli): beats tracks the music with the TypeScript beat tracker, without Chrome (#5634)
* feat(cli): audio answers beats, downbeats, bpm, sections and describe through a provider ladder

Beats and downbeats try api, apple-mu, beat-this, then signal; sections try api, apple-mu,
then signal; describe tries api, then apple-sound. bpm is read off whichever provider placed
the beats. Each provider says whether it can run here and why not, and the ladder warns
when it passes one over.

The signal rung is a TypeScript tracker: log-band spectral flux, autocorrelation tempo with
a log-normal prior, Ellis dynamic-programming beats with a windowed local tempo, a low-band
bar phase, and Foote novelty sections snapped to beats. It reports no steady beat when the
onsets do not repeat.

The api rung posts the audio to HYPERFRAMES_AUDIO_API_URL with HYPERFRAMES_AUDIO_API_KEY and
moves each answered time onto the nearest signal beat within a quarter beat, reporting what
moved and what did not. beat-this runs Beat This! from a configured Python and local weights
and never downloads. apple-sound runs macOS's sound classifier through a Swift helper.
apple-mu reports that Music Understanding needs macOS 27.

words are no longer accepted: they come from hyperframes transcribe.

* docs(cli): audio's beats, downbeats, bpm, sections, describe and their provider ladder

* feat(cli): beats tracks the music with the TypeScript beat tracker, without Chrome

hyperframes beats and Studio's beat detection now share analyzeMusicFromSignal: band energies,
then the spectral-flux tracker in audioRhythm.ts, then each beat's loudness for its strength.
The CLI decodes with the same ffmpeg path as hyperframes audio, so beats no longer launches
headless Chrome. Studio still decodes in the browser and passes every channel.

The old analyzer averaged bpm-detective's tempo with an energy-peak tempo it had only compared
after folding both into one octave, and phased a rigid grid from noisy peaks. On 22 real tracks
with exact script grids it found the tempo 18% of the time with beat F 0.437; this finds it
91% of the time with F 0.887, and refuses the other two rather than guess.

Below a tracker confidence of 0.2 no beats are reported, so ambient or rubato music gets no
invented grid and the CLI still writes nothing. bpm-detective, the energy-peak grid, the
headless analyzer and its prebuilt bundle are gone.

* fix(core): tempo reads 96 BPM off beats on 10 ms frames, not 95.2

The tracker places beats on 10 ms frames, so a 625 ms beat lands 620 or 630 ms apart and the
median interval reported 95.2 or 96.8 BPM. Tempo now averages the intervals within 10% of the
median: as robust to a skipped or doubled beat, without the frame-sized step. Both
hyperframes audio and hyperframes beats read it.

* fix(cli): remove redundant audio context comment

* fix(core): remove redundant tempo interval comment

* fix(ci): record beat analyzer removals and browser evidence

* fix(core): keep flat audio novelty in one section

* chore: keep PR capture evidence out of the source tree

* fix(cli): honor BPM provider pins before analysis
2026-10-15 06:23:03 +00:00
Miguel Ángel d4c8d76fff fix(lint): warn on unbounded cosine powers in shaders (#5640) 2026-10-15 05:40:38 +00:00
Miguel Ángel db845d9409 fix(cli): retire old snapshot run folders (#5635)
* fix(cli): retire old snapshot run folders

* chore: satisfy snapshot comment limit

* fix(history): read and release snapshot leases through verified handles

* test(history): run lease races in Node and check released markers

* fix(studio): verify snapshot leases from open descriptors
2026-10-15 04:59:59 +00:00
Xuanru LiandClaude Opus 5.5 150e1c94d0 fix(cli): report spend usage for Claude plans without rate windows (#5629)
* fix(cli): report spend usage for Claude plans without rate windows

Spend-metered Claude plans (for example Enterprise) return null five_hour
and seven_day windows from the OAuth usage endpoint and put their allowance
in spend / extra_usage instead. The parser rejected every such response as
invalid_usage_response, so `hyperframes usage` always reported unknown.

- Read spend.percent (falling back to extra_usage.utilization) into a new
  `spend` window on known results; over-limit spend caps at fully used.
- Report `no_usage_windows` instead of `invalid_usage_response` when a
  well-formed response simply has no window.
- Document the `spend` field in the hyperframes-cli skill.

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

* fix(cli): satisfy usage budget comment ratchet

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:04:55 +00:00
Miguel Ángel 6f90ca15a7 chore(skills): storyboards are a board of stills with one page format (#5599)
* chore(skills): storyboards are a board of stills with one page format

* chore(skills): count audio_meta.json as a project file in comment citations

* chore(skills): point every board mention at the storyboard recipe

* chore(skills): board redos replace only their own stills, from the mounted composition

* chore(skills): board stills come from the host's snapshot tool when one is offered
2026-10-14 13:56:58 +00:00
Xuanru Li 23d1fe5b42 feat(cli): save check, snapshot and render artifacts per revision (#5522)
* feat(cli): save check, snapshot and render artifacts per revision

* fix(cli): keep clean --snapshots inside the project

A symlinked .hyperframes or artifacts folder was followed, so the command
deleted snapshot and check files outside the project.

* test(cli): keep check, snapshot, and render successful when recording fails

A held history or a corrupt output registry warns and leaves the command result alone.

* fix(cli): drop snapshot records when a replaced run is not recorded

A reused --output rewrites the files even when history is busy.
Those records are removed so the old revision does not keep the new pixels.
The preview checkpoint stops waiting after five seconds.
A bad PNG header no longer fails the snapshot.

* fix(studio-server): keep the video-state comment share from rising

The forget helper's doc comment pushed the file above its base share.

* fix(cli): post the preview checkpoint and keep cleanup inside artifacts

A preview checkpoint with no body was sent as GET, so Studio never ran it.
Cleanup now requires the real path to stay under the artifacts folder.
A failed follow-up drop does not warn twice.
The studio-server unpacked budget covers the record-dropping helper.

* docs(cli): shorten the snapshot skill notes

The command examples already show range and composition.
The prose only keeps the output path and the flags that are easy to misuse.

* chore: leave package headroom for artifact cleanup

* test(cli): compare artifact paths portably

* style(cli): format portable artifact assertion
2026-10-13 06:20:31 +00:00
Miguel Ángel f46033d048 fix(skills): skill scripts run through a symlinked skills dir and agents keep long renders alive (#5396)
* fix(skills): skill scripts run when the skills dir is a symlink

* test(skills): plugin launcher fixture ships the shared main-module helper like an install

* fix(skills): the CLI's cube validator runs through a symlink too, and the guard check is stricter

* docs(skills): long agent-started renders run detached in their own process group

* docs(cli): detached renders start in their own process group, on macOS too

* docs(cli): the detached render recipe never waits on terminal input
2026-10-10 04:54:41 +00:00
Miguel Ángel b20f3f7ad9 fix(cli): check warns instead of failing on a still title card (#5369)
* fix(cli): check passes a still title card whose timeline follows the seek

* fix(cli): check warns on a still frame and fails only when an animation is stuck

* fix(cli): count a seek clock once per sample and point the error at the registered timeline

* fix(cli): judge a finished animation by its own completion state, not its end time

* test(cli): pin a Web Animation paused at its end as finished

* fix(cli): judge a reversed animation's end in its own direction, and read plain timelines

* test(cli): pin a plain timeline held at its end as finished

* test(cli): keep an unfinished plain timeline beside the finished one

* fix(cli): skip a timeline whose time cannot be read instead of calling it stuck

* fix(cli): skip an animation whose time is not a plain number, such as a scroll-driven one

* fix(cli): a partial timeline with plain values no longer stops the browser checks
2026-10-10 00:38:09 +00:00
Abdullah M. Nazif fe38e8fe12 docs(cli): explain FFmpeg setup without a package manager (#5237) 2026-10-08 20:58:47 +00:00
Miguel Ángel cf1b04bb71 feat(cli): accept host-managed HeyGen access tokens (#5177)
* fix(auth): accept host-managed HeyGen access tokens

* fix(auth): share environment header validation

* docs(auth): condense credential resolver guidance

* fix(auth): report the account a browser login just signed in

Identify the account from the tokens the login issued, not a fresh credential
lookup that an environment token or API key outranks.

* docs(auth): list the host access token in the CLI credential order

* fix(cli): name a rejected host access token on publish

Publish told a host-token user to log in again, which cannot help while the token outranks the login.

* docs(auth): show the media credential order main resolves

* fix(cli): warn at logout that a host access token still signs commands

One map of environment credential variables, owned by the resolver, now feeds the logout warning and both publish messages.

* docs(auth): scope the media credential order to the audio scripts

* refactor(cli): read every env credential name from the resolver's map
2026-10-08 10:33:57 +00:00
Miguel Ángel 80c2547eac feat(cli): send missing features and host-app friction as ratingless feedback (#5140)
* docs(skills): ask agents inside a host app to report its friction as feedback

* feat(cli): send missing features and host-app friction as ratingless feedback

* fix(cli): keep the rating error, refuse blank reports and document ratingless feedback

* docs(skills): leave names and figures out of missing-feature reports

* docs(skills): keep anything private out of missing-feature reports
2026-10-07 06:40:37 +00:00
Miguel Ángel 2d98d5c15f fix(check): stop false sweep_static and text-overlap alarms on compositions that are fine (#5147)
* fix(check): see color, filter and media time under seek, and name data-no-timeline for stills

* fix(check): warn instead of fail when only audio advances, and judge text overlap on glyphs

* fix(check): judge glyph overlap by the glyph box, and see capitalized words and one-side borders

* fix(check): capitalize past leading punctuation, test outline color, trim a comment

* fix(check): capitalize words the way Chromium does, so digit-led words stay lowercase
2026-10-07 05:38:45 +00:00
WaterrrForever 6fe3c2ce94 feat(cli): catch up on what the desktop app did since a project was handed over (#5114)
* feat(cli): catch up on what the desktop app did since a project was handed over

The desktop app records each chat turn in .hyperframes/app-history.jsonl.
`hyperframes catch-up [dir]` prints the turns since the hand-off or the last
catch-up (what the person asked, what Framey did, which files changed) plus
the project files changed since, by the app or by hand, then marks them seen.

`hyperframes open` and Studio's Edit with Framey mark the hand-off moment.
Any command run on a project with unseen turns ends with a line naming
catch-up, so an agent back in the terminal hears about it even when it
forgets. /hyperframes and /hyperframes-cli tell the agent to catch up as
soon as the person writes again.

* feat(cli): hand a Grok terminal session over to the desktop app

Grok gives every tool command its session as GROK_SESSION_ID (grok 1.0.4),
so `hyperframes open` and Edit with Framey now name a Grok session in
.hyperframes/agent-handoff.json, after Claude Code and Codex. The desktop
app reads its turns from Grok's own session files.

* feat(cli): tell a new project's agent to catch up after the desktop app

Scaffolded projects' CLAUDE.md and AGENTS.md now say to run
`npx hyperframes catch-up` before the next change once the project was
opened in the desktop app. Claude Code, Codex and Grok read these files on
their own, so a resumed session catches up even when it never loaded a
HyperFrames skill: a resumed Claude Code session that had not, asked to
change the title, ran catch-up first.

catch-up also prints each reply on one line.

* fix(cli): read and write .hyperframes records without following links, mark seen after showing

Review (Jerrai, Rames):
- One helper (projectRecords.ts) now reads and writes every record in
  .hyperframes/. A linked folder is refused. A read opens once with
  O_NOFOLLOW and checks the open file is a plain file, which clears the
  CodeQL race. A write goes to a temp file renamed over the record, so a
  link is replaced, never written through. agent-handoff.json, the seen
  record and the history all go through it.
- catch-up marks a turn seen only after showing it, and only up to the
  newest turn shown, so a turn written just after the read shows next
  time. Changed files have their own "checked" time.
- Turns show only once the project was handed over from this machine, so
  a history file shipped in a cloned repo is never shown as the person's
  words. The end-of-command check skips reading when the history is
  older than the seen record.
- The skills mention catch-up only when the CLI printed a line naming it,
  so an older CLI never meets an unknown command.
- The notice test uses basename, which fixes Windows.

* feat(cli): add the catch-up line to an older project's instructions on hand-off

A project scaffolded before catch-up existed has no line telling its agent
to catch up, and a resumed session that never loaded a HyperFrames skill
then edits without knowing what happened in the app. When `hyperframes open`
or Edit with Framey hands such a project over, its scaffolded CLAUDE.md and
AGENTS.md (they start "# HyperFrames Composition Project") gain the
template's line, in the template's place. A file of the person's own, a
link, a missing file, or one that has the line is left alone. The file is
rewritten through a temp file with its mode kept. A test keeps the line the
same as the template's.

* fix(cli): keep catch-up's cursor in the person's home, never reset it, read without links on Windows

Review (Rames, Jerrai):
- The seen record moved from the project to ~/.hyperframes/catch-up/,
  keyed by the project's real path. A seen file a cloned repo commits
  can no longer make its history read as the person's words.
- A second hand-off (`open` again, or another Edit with Framey click)
  keeps the cursor, so turns the app recorded meanwhile still show.
- Reads lstat the path, open it once, and refuse a file whose dev/ino
  differs from what lstat saw. That holds where O_NOFOLLOW doesn't
  exist, fixing the Windows test. The note writer reads the same way,
  which clears the new CodeQL alert.
- Writes use core's replaceFileAtomically, which retries a rename that
  Windows briefly refuses.
- catch-up names every changed file, and the cursor is the newest `at`
  shown, not the last line's.
- `open --json` carries `catchUp` after a hand-off.
- The bin scripts are back to mode 644.

* fix(cli): open before checking for CodeQL, never show a turn dated ahead

Review (Rames, Jerrai):
- readPlainFile opens the file first, then requires lstat to find the same
  plain file (dev/ino) at the path, and reads only through the fd. That is
  just as safe, and it clears CodeQL's check-then-use alert.
- catch-up skips turns dated after the moment it reads. So a cloned history
  can't show a far-future turn as the person's words or park the cursor
  past real ones.
- The seen key uses core's realpath (realpathSync.native), so letter case
  can't split a project in two. ~/.hyperframes/catch-up is made 0700, and
  a hand-off that can't note itself says so.
- Tests stub HOME with vi.stubEnv and restore it.
2026-10-06 13:20:27 +00:00
WaterrrForever 69a2169bde feat(skills): open Studio before every final render, and pitch the desktop app as the chat way to edit (#4952)
* feat(skills): tell the user about HyperFrames Studio at the final preview and after delivery

/hyperframes gains § 6: mention the preview header's Edit with Framey button when the final
Studio preview opens, and after the delivery render pass on the render's own desktop-app line
in plain words — offer to run `hyperframes open` when the app is installed, else give the
download link. Say nothing when the render prints no such line (a draft, a batch row, a run
inside the app). Builds on the CLI lines added in #4951.

* feat(skills): open studio before every final render, pitch the app as the chat way to edit

Users who only ask for a video never saw Studio: autonomous runs asked "preview
first, or render?" and a "you decide" answer rendered. The final look now opens the
Studio preview in every mode, then asks "render now, or what changes?" — opening it
asks nothing, so it also holds when the user said not to ask.

Section 6 says what is true: the Studio preview already edits and saves; the desktop
app adds editing by chat with Framey. The agent names it "the HyperFrames Studio
desktop app" so it is not mistaken for the preview. general-video, the review loop
and the brief contract carry the same final look.

* fix(skills): call the app the hyperframes desktop app, never studio

* fix(skills): pitch edit with framey only when preview shows it, keep direct renders direct

* fix(skills): mention the button only after the line that ships with it
2026-10-04 12:55:56 +00:00
Miguel Ángel 7348933111 feat(cli): expose harness subscription usage to agents (#4919)
* feat(cli): plan video creation around remaining harness usage

* feat(cli): read Codex and Grok subscription allowances

* test(cli): load usage fixtures through portable file URLs

* test(cli): keep fixture writes on filesystem paths

* refactor(cli): separate usage window and login decisions

* fix(cli): guard parsed credential array entries

* refactor(cli): report harness usage without workflow policy

* fix(cli): preserve usage when subscription tier is null

* test(cli): separate usage fixture code from inputs

* style(cli): format usage transport fixture

* refactor(cli): isolate usage fixture credential checks
2026-10-03 00:25:43 +00:00
miga-heygenandMiguel Angel b31fb02c7e fix(cli): distinguish a skipped browser check from a genuinely clean one (#3901)
* fix(cli): distinguish a skipped browser check from a genuinely clean one

`hyperframes check`'s runtime/layout/motion/contrast JSON sections reported
the exact same ok:true/zero-findings shape whether the browser session
actually ran and found nothing, or never ran at all (a blocking lint error,
a lint-step crash, or an exception thrown before the audit could start all
took the same "empty result" fallback). Only the top-level ok field and an
undocumented layout.duration === 0 tell separated the two cases apart.

Add a skipped boolean to CheckBrowserResult, set at the only two places one
is constructed (false in the real audit result, true in the empty-result
fallback), and mirror it to a new top-level browserSkipped field on
CheckReport. The human-readable report now prints a warning when the
browser never ran; the JSON envelope carries the same signal for callers
that only check individual sections.

Co-Authored-By: Miguel Angel <miguel.sierra@heygen.com>

* docs(cli): document browserSkipped in the check --json envelope

Co-Authored-By: Miguel Ángel <miguel.sierra@heygen.com>

* refactor(cli): trim browserSkipped docs and cover the linter-crash skip path

* chore(skills): refresh the hyperframes-cli manifest hash

* refactor(cli): drop the browserSkipped type comments to keep the comment share flat

---------

Co-authored-by: Miguel Angel <miguel.sierra@heygen.com>
2026-10-02 07:32:48 -07:00
Miguel Ángel 663b02297d feat(cli): add hyperframes clean to find and remove what HyperFrames left on disk (#4701)
* feat(cli): add hyperframes clean to find and remove what HyperFrames left on disk

`hyperframes clean` lists leftover render work dirs, debug renders, the history of projects
that no longer exist, idle video proxies and extracted video frames, with sizes, and removes
them. `--dry-run` removes nothing, `--json` is for agents, `--snapshots` also removes
snapshot folders (otherwise listed as reclaimable). It never touches outputs, sources or
anything a running render or preview still owns.

* docs(cli): say that clean does not search a project's subfolders

* fix(cli): clean test compares folder names on Windows and the skills manifest is regenerated

* fix(studio-server): the proxy cache sweep removes only files the transcoder named

It removed any idle .mp4 or .webm in .transcode-cache, so a user file placed there, or reached through
a symlinked cache folder, could go. Proxies are always <sha256>.<ext> and their temp files
.tmp-<uuid>-<proxy name>; nothing else is swept.

* style(producer): keep a renderDirOwner doc comment within 120 columns
2026-09-29 00:43:42 +00:00
Miguel Ángel fa044a89e5 feat(cli): tag telemetry and feedback with the app that launched the CLI (#4632)
* feat(cli): tag telemetry and feedback with the app that launched the CLI

* fix(cli): keep the client tag to a short slug and correct the telemetry docs

* test(cli): read the delivered batch through the shared helper

* refactor(cli): let the tag pattern alone bound the client tag's length

* docs(cli): describe the client tag generically as the launching app's tag

* style(cli): format the client tag test cases

* test(cli): use a neutral example value for the client tag

* chore(skills): regenerate the skills manifest for the telemetry reference
2026-09-28 05:11:11 +00:00
James Russo ff6e2103d7 fix(skills): keep plugin workflows on their installed release (#4607)
* fix(skills): keep plugin workflows on their installed release

* docs(skills): clarify plugin manifest discovery

* fix(plugins): suppress stale notices and isolate plugin context
2026-09-27 21:05:28 +00:00
Miguel Ángel 2734ee2c02 feat(cli): hyperframes history lists, undoes and restores a project's recorded changes (#4449)
* feat(cli): hyperframes history lists, undoes and restores a project's recorded changes

* fix(cli): an agent's history turn ends after 10 idle minutes on every path

A turn left open no longer takes the person's later edits: the engine
files a CLI turn's writes by the same idle rule as a preview window.
Studio claims take their paths back from an agent's window; refusals,
--json shapes, --limit and time parsing follow the review.

* refactor(cli): the project-history opener lives in its own module

The history command and other commands open a project's history the same
way: through a running preview, or directly under the engine's lock.

* docs(skills): the history loop lines sit in one marked trial block per skill

* fix(cli): a turn marker without its last write time has ended

Idle-limit tests set file times instead of racing the clock, and the
restore refusal test picks a ref no entry id starts with.

* docs(cli): the history entry shape comment names no other app

* refactor(cli): history reuses the busy error class and its who helper

* fix(cli): undo --who reverts the agent's whole last turn and nothing older

When the open turn recorded nothing, undo fell back to the agent's
earlier turn; when a mid-turn command split the turn, it reverted only
the newest part. The turn now keeps the entries it filed, and undo --who
reverts exactly those or refuses. Engine tests pin the write timing
rules, and a date that rolls over (Feb 31) is refused.

* fix(cli): an undo --who that meets a conflict leaves the whole turn as it was

It redoes the parts it already undid, lists the newer entries as they
are now, and offers --just-this and --back-to-before for the whole turn.
The last turn is recorded atomically before its marker is cleared.

* chore(cli): history keeps each file's comment share at or under main's

* fix(cli): history keeps log order past a turn's idle limit and undoes a turn's cut parts

* fix(cli): history drops unused imports and splits undo and reopen steps
2026-09-25 14:26:09 +00:00
Miguel Ángel 7c634426fd docs(cli): explain how catalog search works and which model it downloads (#4462)
* docs(cli): explain how catalog search works and which model it downloads

* docs(cli): name the model catalog search was chosen against

* docs(cli): keep only live rules in the word-search header comment

* docs(cli): correct the hosted vector size in the local vector build comment
2026-09-25 04:43:54 +00:00
Miguel Ángel 7556b95ac6 feat(cli): warn when canvas content touches the frame edge (#4427)
* feat(cli): warn when canvas content touches the frame edge

* test(cli): pin which frame edge the canvas warning reads

* test(cli): type the canvas edge stub like the file's other getContext stubs
2026-09-24 16:04:44 -04:00
Miguel Ángel 05d09a7452 chore(registry): remove low-use catalog items and variant tails (#4274)
* chore(registry): remove low-use catalog items and variant tails

* fix(registry): remove stale references to deleted catalog items

* style: format catalog fixture

* fix(ci): use surviving catalog preview canary

* chore(ci): allow intentional catalog deletions

* fix(ci): scope fallow audit for catalog fixtures

* chore(catalog): regenerate local search vectors

* chore(catalog): update vector revision

* fix(catalog): validate registry set delta
2026-09-22 07:04:54 -04:00
Miguel Ángel 3091dcb787 feat(cli): route media search through media-use (#4230)
* feat(cli): move media-use engine into the CLI

* fix(cli): replace media-use compatibility asset

* fix(cli): replace moved media-use tree

* fix(cli): copy moved media-use files cleanly

* fix(cli): copy media-use engine files individually

* fix(cli): keep audio helper compatibility import

* fix(cli): clear copied skill destinations

* test(cli): preserve moved media-use test paths

* fix(cli): preserve media-use script compatibility imports

* fix(cli): preserve media-use telemetry shim

* fix(cli): resolve packaged media-use LUT assets

* fix(cli): resolve packaged bundled SFX assets

* chore(skills): regenerate media-use manifest

* fix(cli): preserve media-use parity coverage

* fix(cli): cover relocated media-use tests

* chore(skills): regenerate media-use manifest

* fix(cli): format bundled media provider

* fix(ci): run relocated media-use tests with node

* fix(ci): preserve fallow script exemptions

* fix(ci): scope media-use fallow exemption

* refactor(cli): trim media-use essay comments

* feat(cli): index media-use assets for catalog search

* feat(catalog): commit media-use search vectors

* chore(catalog): track media vector metadata

* fix(catalog): validate media vector row order

* fix(catalog): validate media artifact freshness

* fix(catalog): cover media metadata and credits

* fix(cli): reject malformed media rows

* fix(catalog): compare complete media rows

* feat(cli): route media search through media-use

* refactor(cli): trim relocated media-use comments

* fix(cli): make media search runtime-safe

* fix(cli): preserve sfx fallback diagnostics

* fix(cli): probe sfx fallback provider explicitly

* chore(skills): regenerate manifest

* refactor(cli): keep typed media ranker source

* fix(cli): align media search checks with local-first flow

* fix(cli): scope vector audit exceptions

* fix(cli): ship resolver registry beside skill

* fix(cli): keep media-use skill scripts standalone

* test(cli): cover local vector validation

* test(cli): correct media vector fixtures

* fix(cli): prefer exact media keys

* fix(cli): stem exact media keys

* test(cli): skip media lint for snippets without media

* fix(cli): align skills test discovery

Keep the CI skills job's bash discovery as the single source of truth so its empty-list guard covers the exact files Node executes. Make hasMediaVectors private because it has no external callers and needs no Fallow suppression.

* fix(cli): close media-use review gaps

Prioritize literal ids before stemmed ids and cover the collision alongside the plural regression. Add command seam tests for engine discovery, actionable failure, and argv passthrough. Add a deterministic parity check for standalone media-use copies, with documented allowlists for the standalone media-fetch shim and self-contained npx resolver. Keep the bash-discovered skills test list as the CI source of truth.

* fix(cli): lower parity check complexity

Split missing-copy and unallowlisted-drift checks so the parity guard keeps its behavior without a threshold CRAP score.

* fix(cli): close media-use review seams

Run the parity test in the skills job so skills-only edits exercise the same check. Export the verb mapping and inject command dispatch for direct coverage. Keep missing-copy diagnostics separate from drift reads.
2026-09-21 18:35:47 -04:00
Miguel Ángel ac0d8ced2a fix(cli): timeline lists every clip of a kind in one flat list, nested ones included (#4173)
Text: one absolute-start list per kind, nested clips marked with host and file.

JSON: a track's rows hold every clip of that kind; children are index pointers, not copies.
2026-09-19 10:36:30 -04:00
Miguel Ángel 7597b80c95 fix(cli): timeline reports real media durations instead of unauthored (#4169)
* fix(cli): timeline resolves real media durations instead of printing unauthored

Media rows call the shared resolveMediaDuration with an ffprobe source length.

Each row shows its duration source, or pending with the reason a probe failed.

Absolute time (absStart/absEnd) is carried across sub-compositions.

Remote, absolute and parent-relative srcs are never probed.

* fix(cli): timeline probe leaves the authored-duration rule to the resolver

The gate test now launches jobs while slots are held.

* fix(cli): timeline reports a zero-length probe as pending instead of a measurement

A still image or duration-less container is pending with a reason, never duration=media.

The runOneLiner test helper now cleans up its own fixture directory.

* fix(cli): timeline probe is injectable and the fixture path works on windows

Two unit tests used real ffprobe, which the Ubuntu Test job lacks, and the audio

fixture path doubled the drive letter on Windows. describeProject now takes the

measure function, the tests pass a recorded fake, and one real-ffprobe test remains.
2026-09-19 09:27:28 -04:00
Miguel Ángel 0a5c235173 feat(cli): hyperframes timeline prints a project's tracks and clips (#4138)
* feat(cli): hyperframes timeline prints a project's tracks and clips

* docs(cli): list the timeline command

* feat(cli): timeline command reports unreadable lanes; add skill docs

* fix(cli): timeline stays inside the project, shares one start cache, keeps small volumes

* fix(cli): timeline resolves symlinks before the project containment check

* fix(cli): timeline accepts project folders whose name starts with two dots

* refactor(cli): timeline and compositions share the engine's start resolver

* docs(skills): point agents at the timeline command where they decide how to read a project

* fix(cli): timeline prints absolute main-timeline times and the owning file for nested clips

Nested rows carry absStart/absEnd on the main timeline and their owning
file, alongside existing local start/end. Text prints absolute time first,
local time in parentheses. Adds jq/node one-liners for common queries,
tested against a fixture.

* fix(cli): timeline places nested media at the runtime start and tests its query one-liners

A nested media clip with a negative literal data-start was reported later than it plays,
because the raw start was clamped before the host offset was added. The skill's jq and node
one-liners now run against the fixture in the test suite.

* fix(cli): timeline clamps a negative media start to 0 when its host starts at 0

The runtime skips the host-offset formula for a host at t=0 and clamps the start, so the
timeline command now does the same.

* refactor(core): one media-start rule shared by the runtime and the timeline command

The runtime and the CLI each carried a copy of the rule for when a nested media clip's
start takes the host offset, and the copies had drifted. Both now call
resolveMediaStartSeconds.

* test(cli): timeline fixture for a media start written as an expression

parseNumeric and the runtime's parseStrictFiniteTimingNumber are the same function, so the
two callers cannot disagree on what counts as a literal; this pins the expression case.
2026-09-19 04:27:45 -04:00
Miguel Ángel 1a9668b6d6 docs(skills): the agent presents a tailor-made storyboard instead of a Studio board (#4150)
* docs(skills): the agent presents a tailor-made storyboard page instead of a Studio board

Adds the storyboard recipe (decisions first, beat fields, a self-contained
storyboard.html contact sheet, a review round) distilled from the launch
films, and rewrites the review loop, brief contract, storyboard format and
workflow steps that still described the deleted board and comments file.

* docs(skills): reconcile the sketch pass with the beautiful storyboard sheet

Review found: the recipe's storyboard.html cell spec (real fonts, real
colors) contradicted review-loop's own sketch definition (wireframe, no
brand treatment). The sketch is static, not unstyled; only motion is
deferred to the build pass. Also fixes a frame-packet boundary note, a
craft-device citation, and a provenance overclaim.
2026-09-19 01:07:24 -04:00
Miguel Ángel a25da94b77 refactor(studio): remove the storyboard view and its Storyboard/Preview switch (#4140)
* refactor(studio): remove the storyboard view and its Storyboard/Preview switch

* refactor(studio): fold the thumbnail output branches left after the storyboard mode went

* docs(studio): drop leftover storyboard references after the view was removed

* ci: allow the storyboard view deletions in the no-deletions guard

* docs(studio): wrap an over-long comment line in the caption overlay helper

* style(studio): reindent App.tsx after the view-mode wrapper was removed
2026-09-18 23:47:12 -04:00
Aditya Poudyal e4b1832fad feat(cli): add hls output format (#4022) 2026-09-16 21:09:14 -04:00
heygengenesis[bot]andmiguel.sierra 5d2478c6fa fix: report HDR auto-promotion (#3985)
Report HDR auto-promotion consistently from the render media set, including remote media, and make its regression coverage portable across supported paths.

Co-authored-by: heygengenesis[bot] <262951085+heygengenesis[bot]@users.noreply.github.com>
Co-authored-by: miguel.sierra <229591595+miguel-heygen@users.noreply.github.com>
2026-09-16 06:13:24 +00:00
Miguel Ángel f059a6eb53 feat(cli): default BeginFrame, agent blank, and looks quality (#3927)
* feat(cli): render summary names the capture path, gpu mode and stage timings

* fix(lint): drop gsap_exit_missing_hard_kill, its hazard does not reproduce on cold workers

* fix(cli): render slow-path hint fires only when the gpu was auto-probed

* test(cli): isolate agent hint suite from ambient agent env keys

The suite runs inside agent sessions. Ambient env keys fill the 16-key
hint cap and fail assertions that a plain shell would pass.

* docs(music-to-video): drop leftover hard-kill mandate after lint rule removal

Frame workers still required a tl.set hard-kill that the dropped lint
rule no longer enforces. Align the self-check with montage.md.

* refactor(cli): share hint-key pattern and collapse render summary args

Export HINT_KEY_PATTERN for the test isolation strip. Read duration and
frame count from the perf summary instead of passing them beside it.

* test(cli): lock capture-mode preference and 16-key hint isolation

Session mode, including drawelement, must print over observability.
The hint suite now fails if ambient keys already fill the 16-key cap.

* feat(cli): default BeginFrame, agent blank, and looks quality

Local auto render opts out of the software-GPU screenshot clamp so
BeginFrame can run. init --agent scaffolds a centered Inter blank with
no prompts. --quality looks (now the default) is CRF 16; delivery is high.

* fix(cli): honor screenshot env and teach agent pitfalls on the happy path

Local auto still requests BeginFrame unless PRODUCER_FORCE_SCREENSHOT=true.
The agent blank fills its canvas so --resolution can resize it. Skills now
name the four pitfalls and tell agents to read the render summary line.

* feat(cli): default init to the centered blank

Bare init scaffolds the centered Inter stage. --agent is a hidden alias.

* fix(cli): pack from-file and use it for video init

TTY --video with no --example selects from-file. Pack copies that template.

* fix(cli): wire --video onto from-file even with --example blank

One resolver picks the scaffold. Spawned init --video asserts a-roll src.

* fix(cli): narrow looks CRF on the quality alias

Only looks carries crf. Typecheck failed on the union without a guard.

* style(cli): shorten render-pipeline summary comment
2026-09-13 21:44:19 -04:00