* fix(engine): a video on a non-square pixel grid renders at its display shape
* chore(engine): drop comments the names already carry
* fix(engine): a rotated clip with a non-square pixel grid keeps its display shape
* test(engine): the frame probes end their options with -- like every ffprobe call
* fix(cli): anonymous hosts and host in-points move a caption word's lifetime window
* fix(cli): a host's end and playback-start are read like the runtime reads them
* fix(engine): a render no longer waits for a sub-composition timeline no script can register
* fix(engine): the timeline wait matches a twice-mounted id and a template-literal key
* fix(cli): browser clear still reports a folder Windows holds, and the EBUSY test covers EPERM
* fix(cli): browser clear reports a locked browser folder, with a test that fails if it does not
* fix(cli): text-to-speech ignores a foreign PYTHONPATH when it looks for kokoro-onnx
* fix(cli): shorten the pythonEnv comment
* fix(cli): text-to-speech keeps a deliberate PYTHONPATH unless the packages fail with it
* fix(cli): drop the python.ts comments the names already say
* fix(core): the playhead keeps moving at a cut while the incoming take has not started
* fix(core): shorten a comment in the clock
* fix(player): keep the WebKit stops script out of the type check
* fix(core): cut two comments from the clock
* fix(core): a still sub-composition's data-no-timeline on its template root skips the timeline wait
* chore(core): drop a comment the copy already says
* fix(cli): check flags caption words hidden behind a cut-out and ignores a mostly transparent cover
* fix(cli): a caption word's lifetime is shifted only by its composition hosts
* fix(cli): normalize-audio never cuts a clip that is quieter than the target
* fix(cli): carry the boost-hold rule in a name, not a comment
* fix(cli): normalize-audio no longer says a clip is matched when a limit holds it short of the target
* fix(cli): format normalize-audio, drop the extra comment, and say a held clip is held
* fix(cli): Apple Silicon Macs without ffmpeg get working arm64 ffprobe and ffmpeg
* fix(cli): drop the bundled ffmpeg installers, name the x86-only binary it skipped
* 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
* test(cli): stalled-download tests give each stall time for its bytes to reach disk
* test(cli): a stalled download times out once its bytes are on disk, not on a clock
* feat(studio): a preview reload that gives up on the runtime says how far the page got
* refactor(studio): read the reload's page phase in one place, before the frame is let go
* test(studio): every reload page phase is covered, and the hook gains no branch for it
* refactor(studio): the reload page phase reads the window only once the frame has a document
* fix(cli): a project .env only sets the CLI's own settings
The .env in the working directory could set any environment variable for every
command except capture. It now sets only the keys the CLI reads from a project:
the HeyGen, ElevenLabs and Figma credentials and the vision keys, models, Vertex
settings and timeout. Other keys are ignored, and one stderr line names them.
* test(cli): the startup test and comment budget follow the single project .env key list
* fix(cli): a project .env can still turn telemetry off
* fix(engine): late-starting videos play to their last frame
A video whose first frame is after timestamp 0 could end early (frozen
tail) or late: ffprobe's stream duration does not run from the first
frame in every container (fragmented MP4, Matroska). Such a video's end
is now read from its last packet, once, where its facts are probed.
* test(engine): the WebM-with-audio case measures its first frame from the file
* test(engine): the first-frame probe ends its arguments with the input file
* fix(core): the preview's scene window settles when a scene can't unmount instead of hanging the page
* refactor(core): name the scene window's stuck step instead of commenting it
* fix(cli): allow-occlusion on the covering element silences text_occluded
* fix(cli): allow-occlusion also works on graded video and does not excuse a card's own text
* fix(engine): long films start capturing at once instead of after a full effect scan
* fix(engine): give the effect scan two minutes, under the app's stall limit
* fix(engine): show effect scan progress so a long scan reads as preparing, not stalled
* fix(core): telemetry redaction covers folders with spaces in any script
* style(core): shorten the redaction folder note
* fix(core): spaced folders without a root redact only before a file name
* style(core): drop the redaction note that described the leak as intended
* style(core): two fewer comment lines in the redactor
* fix(core): bound the spaced-folder match so long lines stay linear
* feat(cli): a feedback report names why the last check failed
* fix(cli): feedback names a check that threw or never finished, with when it ran
* fix(cli): feedback says how old the last check is
* fix(player): iPhone Safari keeps every take's sound after the first seconds of an edit
* fix(player): shorten the priming comment
* fix(player): prime iPhone takes only, and only unmuted ones
* fix(player): shorten a comment
* fix(player): skip only clips authored muted, and drop a doc comment
* ci: one regression shard writes the test image cache, so it stops evicting the rest
* test(ci): each image cache has one writer, shard 0 of a main push
* fix(cli): a snapshot still shows what playback shows, whatever other times are asked for
* test(cli): pin that still-capture pages ask for the skipped-frame replay
* perf(cli): give render the heap its auto workers need in small containers
Auto worker sizing caps capture workers at (V8 heap - 1024 MB) / 640 MB.
Node sizes its default heap from visible memory, so in a 10 GB container
the heap is 2,096 MB and every render captures with one worker, whatever
the core count.
When no --workers is given, no --docker, no heap was set by hand, and the
heap is the only bound holding workers back, render relaunches itself once
with --max-old-space-size set to what CPU and memory allow (capped at half
of memory). The engine exposes heapMbForAutoWorkers() for this.
* fix(cli): count a heap-relaunched render once, keep detached renders alive
The relaunched child skips the CLI's command telemetry, update and skills
notices, and app-history notice; the parent already records and prints
them. A detached render no longer gets SIGHUP forwarded, which its
default handler would treat as a kill. A heap set as --max_old_space_size
counts as set by hand.
* fix(engine): keep the desktop app's per-worker heap figure at 640 MB
Inside Electron the heap is a hard 4,192 MB cage, and that is where the
field OOM behind the old figure happened (#5149: 5 auto workers on a heavy
export). The new 320 MB figure is measured only in a system Node, so the
desktop app keeps 640 MB (4 workers there) until a heavy desktop export is
measured. Containers and plain Node keep 320.
* fix(engine): know the packaged desktop app by its client tag, which runs the CLI on plain Node
* fix(ci): skills sync steps past any taken ClawHub version, not one hard-coded skill
* fix(ci): skills sync steps past the five hidden ClawHub versions blocking it
* fix(cli): an unknown command like search says which command does that
* fix(cli): the synonym hint is checked before the spelling match, so list, find and browse reach it