* feat(cli): write one diagnostic report when a command stays silent for 60 s
* feat(cli): load the hang report only when it is asked for
* fix(cli): the hang report is written without announcing itself on stderr
* fix(cli): the hang report leaves out environment values or is not written, and is written once
* refactor(cli): shorten the hang report comment to the line limit
* fix(cli): history show --diff works without git on PATH
* fix(cli): unifiedDiff passes lint and fallow: blocks, shared direction rule, split test
* refactor(cli): split the diff walk and its backtrack into small steps
* 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
* chore(cli): tag the studio download link with where it was shown
The terminal hint, hyperframes open and the browser editor button now add
src=cli or src=browser-editor to the download link. The download route
already records src, so these downloads stop landing in no source.
* chore(cli): drop the DownloadSource doc comment the type name already says
* chore(cli): leave the no-build fallback link untagged, since only the download route reads src
* fix(cli): check and snapshot fail fast on a missing browser path and say while Chrome downloads
* fix(cli): a non-interactive Chrome download gives up after one stall, naming the env var and doctor
The hyperframes package had no homepage, so npm linked the GitHub
readme. The publish job rewrites only the name, so this field reaches
npm on the next release.
* fix(check): a mask that cuts descenders and a shared scene's own selector are handled
* test(core): update the page-build goldens for the scoped selector rewrite
* fix(core): a shared scene's authored-id selector rewrites to the mount without a second pattern
* fix(cli): the Windows Chrome check launches Chrome instead of trusting chrome.exe --version
* refactor(cli): shorten the Windows Chrome version comment to fit the comment ratchet
* test(cli): pin the platform in the Unix Chrome preflight tests so Windows runs them as written
* fix(cli): the Windows Chrome check reads the file version, not chrome.exe --version
* fix(cli): Windows preview and catch-up records move to LOCALAPPDATA, a refused log no longer blocks
* fix(cli): a refused preview log falls back to the null device and drops the extra comments
* fix(cli): Windows catch-up record goes under LOCALAPPDATA/hyperframes like the other records
* fix(cli): the check and snapshot project lock works where hard links are refused
* refactor(cli): drop the project lock comment to fit the comment ratchet
* fix(render): a PNG's colour tags no longer change its pixels in preview, check, snapshot or render
* fix(render): the play and present server also serves a PNG without its colour tags
* fix(render): bundled pages inline a PNG without its colour tags too
* fix(snapshot): video frames keep the colours render gives the same footage
* fix(snapshot): say so once when video colours cannot be matched to render
* test(snapshot): cut the HEVC fixture's encode time so the flake gate stays inside its timeout
* style(snapshot): format the HEVC fixture line
* fix(producer): convert HEIC images to JPEG at compile time
Tiled HEIC photos probe as several video streams, so the media-type
preflight rejected them as image:video, and Chrome cannot decode HEIC.
Sniff the ftyp brands of every <img>, join and rotate the tile grid with
ffmpeg, verify the declared size, and swap in a cached JPEG.
* fix(producer): shorten the HEIC prep comments
* fix(producer): name host tool failures and keep a failed HEIC preview image as authored
Also: HEIC tests run in the integration lane; the primary grid is picked by default disposition.
* chore(producer): raise the package size budget for the HEIC prep
* feat(cli): check catches audio the render would lose or play as silence
check gains an Audio section, read from the media list the render mixes:
- error: a clip's source has no audio the render can read (its mix fails,
the film ships without sound)
- warning: a clip starts past the end of its file, or the part it plays
is silent
- info: the film has no sound at all
The bundle and media list are now built once and shared with the HDR
inspection; the audio pass runs while the browser pass does.
Fixes#2775
* fix(cli): check reports an unreadable audio source the way render handles it
A source with no audio track is refused by render's own media-type rule, now exported from the producer and called by check; a source that does not decode as audio fails the mix and stops the render.
* perf(cli): check samples a long clip at a few spots before reading all of it for silence
Sound at any spot ends the decode; a clip is only called silent after its whole played part is read.
* chore(cli): drop a comment the shared finding helper's name already says
* feat(cli): hyperframes <dir> opens the project in the app
* refactor(cli): one command-word lookup and one rewritten command line for the folder shortcut
* refactor(cli): shorten the folder shortcut comments to fit the comment ratchet
* fix(media-use): serialize concurrent preference records
* chore: prepare conflict resolution against current main
* fix(media-use): serialize concurrent preference records
* docs(media-use): clarify project preference file guidance
* chore: prepare conflict resolution against current main
* fix(media-use): refresh preference records against main
* chore: prepare conflict resolution against current main
* chore: merge main and refresh preferences skill manifest
* chore: prepare conflict resolution against current main
* chore: merge main and refresh preferences skill manifest
* chore: prepare conflict resolution against current main
* chore: merge main and refresh preferences skill manifest
* fix(cli): preserve UTF-8 across subprocess output chunks
* chore: prepare conflict resolution against current main
* fix(cli): retain UTF-8 output handling with current main
* chore: prepare conflict resolution against current main
* fix(cli): retain UTF-8 decoding with process teardown updates
* chore: prepare conflict resolution against current main
* fix(cli): preserve decoded subprocess progress on current main
* docs(cli): scope Unicode output guarantees to cancellable workers
* docs(cli): name commands with Unicode-safe diagnostics
The examples topic listed title-card and video-edit, which do not exist,
and none of the eight examples in registry/examples. List blank plus the
registry examples with their registry-item descriptions, and add a test
that fails when the topic and registry/examples disagree.
Fixes#5393
* 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.
* feat(cli): check-review findingFrames saves one plain frame per finding time
With HF_TOOL_CONTEXT check-review.findingFrames, every error/warning finding in
layout or contrast with a real bbox gets frameTime (the middle sample of its
longest held run, by the heldMs gap rule) and frame (the absolute path of an
unannotated full frame shared by every finding at that time). One seek and
screenshot per distinct time, capped at 60 times with errors first, into the
run's snapshot folder; not listed in snapshots, history or events. Without the
capability, output is unchanged.
* docs(cli): finding-frame comments name the check-review capability, not a flag
* fix(cli): validate finding frame times and preserve cancellation
* fix(cli): count finding frame progress toward the check deadline
* feat(cli): check-review inspect attaches the inspector's report to each framed finding
With findingFrames on, the finding-frames page is served with the
inspector's GSAP hooks. After each frame is captured, every finding framed
at that time is inspected by its data-hf-id, else its selector, and the
inspector's own report is attached as the finding's inspect field. A failed
inspection becomes that finding's { error } and never fails the check.
Without the capability nothing changes.
Drops the unused @types/mime-types devDependency that the dependency audit
flags once packages/cli/package.json is touched.
* fix(cli): stop finding inspections after cancellation
* fix(cli): reject ambiguous finding inspection targets
* fix(ci): build inspector before Windows CLI smoke
* fix(cli): parse viewport HTML with explicit server parser
* 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.
* feat(cli): check-review findingFrames saves one plain frame per finding time
With HF_TOOL_CONTEXT check-review.findingFrames, every error/warning finding in
layout or contrast with a real bbox gets frameTime (the middle sample of its
longest held run, by the heldMs gap rule) and frame (the absolute path of an
unannotated full frame shared by every finding at that time). One seek and
screenshot per distinct time, capped at 60 times with errors first, into the
run's snapshot folder; not listed in snapshots, history or events. Without the
capability, output is unchanged.
* docs(cli): finding-frame comments name the check-review capability, not a flag
* fix(cli): validate finding frame times and preserve cancellation
* fix(cli): count finding frame progress toward the check deadline
* 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
* 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
* 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
* fix(cli): preserve quoted multiline .env values
applyDotEnv parsed .env content line by line: a quoted value's closing
quote was only ever looked for on the same physical line, so a value
like HYPERFRAMES_VERTEX_SERVICE_ACCOUNT='{...}' spread across several
lines got truncated to the leftover text on its opening line, and the
continuation lines were silently dropped (no "=" to parse as entries).
Join physical lines into logical ones before parsing: when a line
opens a quote that isn't closed on that same line, keep appending
following lines until one contains the closing quote character. This
matches how Node's util.parseEnv treats quoted multiline values.
Fixes#6075
* fix(cli): do not let a commented or unclosed quote swallow later .env lines
logicalLines looked for an open quote on every physical line before
entryOf had a chance to classify it as blank or a comment, so a
commented-out example like `# KEY="sk-old` (an unclosed quote inside
a comment) opened a quote that never closed, joining every line below
it into one value and dropping the real keys that followed.
A genuinely stray unclosed quote with no later closing line had the
same failure mode: the join ran to EOF and swallowed the rest of the
file instead of leaving the malformed line on its own, so a later
file like A='x / B=2 lost B entirely.
Skip blank/comment lines before checking for an open quote (matching
entryOf's own skip), and if the closing-quote search reaches EOF
without finding one, fall back to the opening line on its own and
resume parsing from the next line. Also strip a trailing \r per line
so a CRLF multiline value doesn't carry it into the joined string.
* fix(cli): trim comments on dotEnv.ts to stay within the comment-ratchet budget
Dropped the comments on openQuoteOf and closingLineIndex (their names
already say what they do) and cut the logicalLines comment down to
two lines, bringing the file back to 6/93 comment lines against the
base's 4/57.
A dry run hashed every referenced media file in full to look for an earlier upload, strictly one at a time, and printed nothing under --json until the end. It now hashes only files the local upload cache could hold (a file whose size matches no cached asset, or any file when nothing was uploaded, cannot hit), and --json writes one progress line per file to stderr.
* fix(cli): media-treatment and normalize-audio find clips inside mounted scenes
* fix(cli): report the scene file with forward slashes and drop added comments
* fix(cli): normalize-audio reads a scene's audio relative to the scene file
* fix(cli): stop shipping an env var name that endpoint scanners flag
Cisco Secure Endpoint ships an IoC signature that matches the literal
name of the openclaw state-dir env var. Any file containing it is
quarantined, which deletes a CLI dist chunk (the CLI then fails on its
second run) and the Studio app.asar.
Key the openclaw agent-runtime rule on OPENCLAW_CONFIG_PATH only. openclaw
sets both variables on the subprocesses it spawns, so detection is
unchanged. Drop the state-dir name from the comments and from the test,
which now covers detection through the config-path variable.
Fixes#5245
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): keep the openclaw comment under the comment-share ratchet
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cli): drop the external-repo citation from the openclaw comment
The comment-citations check resolves file:line references against this
repo, and that path lives in the openclaw repo.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
snapshot uploaded every frame to Gemini whenever GEMINI_API_KEY or
GOOGLE_API_KEY was set, even with no flag. Frames now stay local unless
--describe is passed. A bare --describe uses the default prompt (it used
to send an empty one), --describe "question" asks a custom one, and
--describe false still works.
Fixes#6138
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>