Commit Graph
1947 Commits
Author SHA1 Message Date
miga-heygenandMiguel Ángel 1de8b5ae33 fix(cli): reject a swallowed --json when catalog's string flags have no value (#3992)
* fix(cli): reject a swallowed --json when catalog's string flags have no value

catalog --query --json (missing --query value) parsed as query="--json",
json=false, since citty's parser (node:util.parseArgs, strict: false)
unconditionally consumes the next token as a string arg's value with no
guard against it being another flag -- JSON-mode consumers silently got
human-readable stdout instead of a clear error.

Added an opt-in rejectSwallowedFlagValues() check (packages/cli/src/utils/
reject-unknown-flags.ts), called from catalog's own run() for its
query/type/tag string args. Kept it opt-in rather than wiring it into the
global assertKnownFlags pre-parse gate every command goes through: check.ts's
--frame-check is a string flag that's documented and tested to work bare or
immediately followed by another flag, handled by that command's own raw-args
preprocessing before citty parses it -- a blanket pre-parse check can't tell
that case apart from this bug, so review caught it as a real regression
before it shipped.

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

* fix(cli): unify swallowed-flag-value handling into one raw-args gate

catalog --query --json (round 1's fix) turned out to be one instance of a
codebase-wide gap: any command with a type:"string"|"enum" flag followed by
--json (or any other declared flag) has its value swallowed by citty's parser
(node:util.parseArgs, strict: false unconditionally consumes the next token),
confirmed still reproducing on check --layout --json. Round 1's post-parse,
catalog-only check also duplicated check.ts's own existing --frame-check
raw-args mechanism instead of replacing it, and couldn't distinguish the
always-legitimate --query=--json (equals form) from the actual --query --json
swallow, since node:util.parseArgs parses both to the same object.

Replaced with a single raw-args scan (guardSwallowedFlagValues), wired into
the global wrapCommand gate next to assertKnownFlags so every command is
covered. Default: throw CliUsageError. Two narrow per-command opt-outs where a
command already has its own bespoke handling for this exact bug shape:
check's --frame-check (rewritten to --flag=, folding in and removing check.ts's
own normalizeFrameCheckRawArgs/swallowedOptionError) and upgrade's --project
(left untouched, since it already recovers the swallowed value itself). A
third, previously-undiscovered collision surfaced during testing: init.ts had
its own bespoke --example dash-value guard that the new global gate now
preempts; folded that in too and updated its one affected test's expectation.

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

* fix(cli): stop the swallowed-flag usage error from leaking to stdout

Round 2's guardSwallowedFlagValues threw CliUsageError without
presented:true, the first non-presented CliUsageError construction in the
CLI -- executeCli's dead stdout-usage-dump branch (every other CliUsageError
goes through failUsage(), which always sets presented:true) fired for the
first time, leaking 1.4-5.7KB of ANSI usage text onto stdout on top of the
correct stderr message, breaking --json callers' clean-stdout contract on
exactly the class of error this ticket exists to fix.

Split into two functions instead of one, since the two throw sites have
genuinely different reach: throwSwallowedFlagError (used by
guardSwallowedFlagValues, thrown before any command's own run() executes)
prints the message itself and sets presented:true, matching every other
print-then-failUsage() usage-error site in this codebase. swallowedFlagUsageError
(used by check.ts's parseFrameCheck) is a plain, side-effect-free CliUsageError
factory, because that throw is always caught by check.ts's own run() try/catch,
which already prints and presents every error uniformly -- using the printing
variant there instead produced a real, verified regression (a doubled stderr
line in non-JSON mode, an extra stderr line even in --json mode), caught by
adversarial review before it shipped.

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

* test(cli): assert literal stdout bytes stay empty for the swallowed-flag error

The prior test for this only asserted the internal presented:true flag, with
a comment noting the actual 0-byte-stdout behavior was checked by hand
against the built CLI. Added an automated spawn-based test (same pattern as
init.test.ts's runInit) that runs the real CLI and asserts stdout is
literally empty, not just that the presented mechanism is engaged.

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

* refactor(cli): split the swallow guard into small helpers to clear the audit gate

Moves the leaf flag checks out of the wrapCommand run arrow, drops ignored args
from the owner map, and pulls the per-token decision out of the guard loop.
Trims two comments to keep check.ts under its comment share. No behaviour change.

* fix(cli): swallow guard hints a value and lets --no- negations through

* fix(cli): swallow guard looks past --no- negations that citty drops

---------

Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com>
2026-10-09 21:55:42 +00:00
Miguel Ángel 5ec2dd2e12 fix(lint): check passes valid sub-compositions and scene-relative asset paths (#5337)
* fix(lint): check passes valid sub-compositions and scene-relative asset paths

* fix(lint): keep the browser lint build free of node modules

* refactor(lint): tidy sub-composition lint helpers and guard bare node imports

* fix(lint): resolve stylesheet asset paths from the stylesheet's own folder

* fix(lint): catch every written form of a path that climbs out of the project

* fix(parsers): sub-composition asset paths written with backslashes load in preview

* fix(parsers): an encoded backslash stays in the file name and a leading backslash stays absolute

* fix(lint): an encoded %2f counts as a separator when checking for a climb out of the project
2026-10-09 19:54:58 +00:00
Miguel Ángel ce73339b1a fix(cli): mirror skills into every installed agent on Windows (#5367)
* fix(cli): mirror skills into every installed agent on Windows

* fix(cli): motion shots can overwrite their previous png on Windows
2026-10-09 19:51:24 +00:00
Miguel Ángel ce359d91cb fix(cli): renders on Windows stop cancelling when an old parent's pid is reused (#5358)
* fix(cli): renders on Windows stop cancelling when an old parent's pid is reused

* test(cli): a Windows parent created in the same tick as its child stays an ancestor
2026-10-09 19:24:06 +00:00
Miguel Ángel 0241078560 fix(cli): name the unzip errors when every Windows unzip tool fails (#5355)
* fix(cli): name the unzip errors when every Windows unzip tool fails

* fix(cli): a cached empty or folder Chrome counts as missing, not found

* fix(engine): skip an empty cached Chrome the same way the CLI does

* fix(engine): keep scanning the Chrome cache past a build it cannot read

* test(engine): a folder at the cached Chrome path is skipped
2026-10-09 19:18:27 +00:00
Abdullah M. Nazif 9c1d3fbe62 fix(cli): preserve subtitle cues across line endings (#5223)
* fix(cli): preserve subtitle cues across line endings

* refactor(cli): preserve newline handling while reconciling subtitle tests

* refactor(cli): normalize WebVTT line endings at the parser

* style(cli): format the retained subtitle test block
2026-10-09 18:03:12 +00:00
Abdullah M. Nazif d03e41c9b4 fix(cli): undo complete timeline batch receipts atomically (#5279)
* fix(cli): undo complete timeline batch receipts atomically

* test(cli): retain both timeline suites before merging main
2026-10-09 17:55:56 +00:00
Miguel Ángel 577bdf6701 fix(cli): browser ensure fails when the unzip leaves no Chrome executable (#5329)
* fix(cli): browser ensure fails when the unzip leaves no Chrome executable

* refactor(cli): keep install debug output and report only the last unzip attempt

* fix(cli): browser ensure exits after a failure or a --force download

* fix(cli): browser checks name why Chrome could not be installed

* fix(cli): render shows why its setup step failed instead of a crash dump

* refactor(cli): build the browser download label and staged test path once

* refactor(cli): one owner for the render setup result line

* fix(cli): render setup failures report through one error line

* refactor(cli): one reader and writer for both render setup lines
2026-10-09 16:21:46 +00:00
Miguel Ángel 63a7ec692f feat(registry): eight more WebGPU shader backgrounds and a bundle with thirty new shaders (#5191)
* feat(registry): eight more WebGPU shader backgrounds and a bundle with thirty new shaders

* refactor(registry): simpler bundle copy step in the shader build

* test(registry): every shader block ships the same bundle and names a shader in it

* refactor(registry): one block loader for the shader block tests

* test(registry): name the stale block and match only shader names

* chore(registry): shorter licence line at the top of the shader bundle

* test(registry): every shader block installs the bundle's licences
2026-10-09 08:52:03 +00:00
Miguel Ángel 0576b24c75 feat(cli): models list shows which speech models transcribe can use (#5323)
* feat(cli): models list shows which speech models transcribe can use

* refactor(cli): models list and transcribe share one Parakeet runner check

* fix(cli): models list skips whisper links transcribe would download again

* style(cli): keep models list comments under the package share
2026-10-09 07:21:54 +00:00
James RussoandClaude Opus 5.5 3aa68869f7 chore: release v0.8.143 (#5302)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 23:28:49 +00:00
Abdullah M. Nazif 1fac5fb29d fix(cli): preserve literal WebVTT cue text (#5236) 2026-10-08 21:16:36 +00:00
Abdullah M. Nazif 83b2f5608f fix(cli): bound timeline bars for negative media starts (#5239) 2026-10-08 20:36:35 +00:00
Abdullah M. Nazif b32ce10b77 fix(cli): audit text beneath transparent composition boxes (#5202) 2026-10-08 20:35:23 +00:00
Abdullah M. Nazif f802aedb5b fix(cli): recognize ancestor gradient text masks (#5207) 2026-10-08 20:30:29 +00:00
Abdullah M. Nazif ee64ebe338 fix(cli): route timeline project directories to inspection (#5240) 2026-10-08 20:27:38 +00:00
Abdullah M. Nazif 1094b8ef0e fix(cli): honor authored durations when listing compositions (#5265) 2026-10-08 20:24:39 +00:00
Abdullah M. Nazif 7faff8154f fix(cli): preserve speaker labels in WebVTT cue text (#5233) 2026-10-08 20:24:19 +00:00
Abdullah M. Nazif 5a7ada63bf fix(cli): validate the complete TTS speed argument (#5264) 2026-10-08 20:20:37 +00:00
Abdullah M. Nazif c9c9f4d363 fix(cli): preserve caption text inside script blocks (#5226) 2026-10-08 20:18:26 +00:00
Abdullah M. Nazif f5aeecdbf4 fix(cli): retain WebVTT timestamps before cue settings (#5224) 2026-10-08 20:18:15 +00:00
Abdullah M. Nazif 2295ed5ea6 fix(cli): encode background-removal WebM colors as BT.709 (#5278) 2026-10-08 20:13:46 +00:00
Abdullah M. Nazif 072de48e08 fix(cli): reuse duplicate Figma nodes within asset batches (#5276) 2026-10-08 20:12:02 +00:00
Abdullah M. Nazif b1aa71d7d5 fix(cli): recover stale media cache entries (#5269) 2026-10-08 20:11:35 +00:00
Abdullah M. Nazif 320de3973b fix(cli): preserve voice placement when ducking empty transcripts (#5271) 2026-10-08 20:09:19 +00:00
Abdullah M. Nazif e6e5f68eba fix(cli): select media streams before reading adopted metadata (#5270) 2026-10-08 20:09:07 +00:00
Abdullah M. Nazif c9ddbd2d42 fix(cli): report snapshot contact sheet failures (#5196) 2026-10-08 20:08:53 +00:00
Abdullah M. Nazif 85360f370a fix(cli): explain hardware GPU screenshot fallback (#5200) 2026-10-08 20:07:01 +00:00
Abdullah M. Nazif 037f731280 fix(cli): close unused download responses before following redirects (#5261) 2026-10-08 20:06:42 +00:00
Abdullah M. Nazif 58b7a4662d fix(cli): serve empty project assets without a stream error (#5234) 2026-10-08 20:03:36 +00:00
Abdullah M. Nazif b407178f3a fix(cli): validate cached versions in update metadata (#5214) 2026-10-08 20:02:44 +00:00
Miguel Ángel 621ddd4693 fix(studio): stop file names with %, apostrophes or $ from breaking Studio (#5156)
* fix(studio): serve files whose name has a bare percent sign

A browser sends src="100%.png" with the % unescaped, and decoding the whole path threw, so Studio answered 500. Only well-formed escapes are decoded now.

* fix(cli): serve files with a bare percent sign from the check and snapshot server

One shared decode rule for request paths; the image thumbnail route's malformed-escape 400 could no longer fire, so a name that is not a file is a 404.

* fix(cli): name a failed file with a bare percent sign in check

* fix(studio): keep apostrophes and dollar signs in file names when editing attributes

An attribute value is matched by its own quote kind, so src="it's.png" is replaced instead of duplicated, and every insert uses a function replacer, so $1 or $& in a file name is written as is.

* fix(studio): rename references spelled with %20 or &amp; and read quoted media sources

WIP: not yet tested; see the resume note.

* fix(studio): match whole attribute names when editing media sources

* fix(studio): compare decoded names and escape replacement references

* fix(studio): preserve file references across URL and string consumers

* docs: clarify raw file references and URL fields

* fix(studio): keep raw path identity distinct from URL spelling

* fix: share attribute grammar and decode media URLs at their readers

* fix: preserve local filename identity in HTML URL output

* fix: decode entity references before rename candidate matching

* style: format rename entity handling and regressions

* fix: preserve platform file identity when renaming references

* fix(core): decode CSS escapes before rebasing asset URLs

* fix(core): consume CSS continuations before URL encoding

* fix(core): preserve CSS URL identity and escape rebased suffixes

* fix(core): express CSS suffix controls with Unicode categories

* fix(core): preserve URL backslash identity while rebasing

* test(core): respect platform backslash filename semantics

* fix(studio): a dropped file with %, # or ? in its name loads, and an encoded reference renames

* fix(studio): read an authored src as a URL so dropped files with spaces, %, # or ? load

* fix(studio): media routes find files named with ? or #, and the probe reads a src as a URL

* fix(studio-server): one rule for request file paths, so loudness finds files named with %, # or ?

* chore: drop the design note from the change

* fix(core): rename replaced clips whose src is URL-encoded
2026-10-08 16:37:49 +00:00
Miguel Ángel 0b21016905 chore: release v0.8.142 (#5257) 2026-10-08 16:34:18 +00:00
Miguel Ángel c7d41dee5a fix(cli): enforce capture screenshot limits and report interruptions (#5171)
* fix(cli): enforce capture screenshot limits and report interruptions

* refactor(cli): split screenshot step out of capture animation phase

Keeps the screenshot limit outside the mirrored core-extraction argument
list and moves scroll screenshots into their own step, so both stay under
the audit's duplication and complexity gates with no behaviour change.
2026-10-08 15:41:50 +00:00
Miguel Ángel 8dae5ef89b fix(core): make grading writes previewable and honor computed properties (#5157)
* fix(core): write only authored hue curves, so a single hue curve passes lint

* fix(cli): apply over a grading saved with empty hue curves instead of refusing it

* fix(core): read grading properties from computed style, and stop advising an inline start

* fix(cli): preserve validation during legacy hue repair

* fix(cli): preview grading writes without apply
2026-10-08 15:21:47 +00:00
Miguel Ángel 188475aaf2 fix(cli): group sampled check findings by element and rule (#5174)
* fix(cli): group sampled check findings by element and rule

* fix(cli): preserve unique elements when grouping audit samples

* fix(cli): retain geometry sample times until report grouping

* fix(cli): keep grouped finding evidence time paired with geometry
2026-10-08 10:38:45 +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
Xuanru LiandClaude Opus 5.5 4a335aa6a1 chore: release v0.8.141 (#5193)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:56:58 +00:00
Miguel Ángel 5c7f6316d3 chore: release v0.8.140 (#5175) 2026-10-07 10:04:56 +00:00
Miguel Ángel e21ab020da fix(cli): preserve transcribed words before speech onset (#5164) 2026-10-07 07:46:58 +00:00
Miguel Ángel dbb8222c8d fix(studio): catch up the preview after missed file changes (#5126)
* fix(studio): recover previews after missed file changes

* fix(studio): keep queued reloads with the current owner

* fix(studio): keep a queued outside change when switching compositions

* test(cli): the project watcher closes its parent folder's watch too

* fix(studio): keep the project-folder change out of the shared signature check

* fix(studio): keep the edited file's draft and reload every session after a reconnect

A reconnect or replaced folder is a project-wide change: every open SDK session reloads, a failed save is recorded against the file the draft belongs to, and two queued changes to different files merge into one project-wide reload.

* fix(studio): refresh the preview cache when the .hyperframes folder is replaced

* fix(cli): report the files of a folder moved into the project

Replacing a populated folder such as .hyperframes/ now reaches the signature cache through its files, so the shared signature rule stays as on main and Studio's own writes inside .hyperframes/ still invalidate nothing.

* refactor(studio): name the merged file-change payload and share the test sender

* fix(studio): keep a failed draft's recovery copy until that file itself saves

* style(studio): rewrap the merged payload line after the rename

* fix(studio): deliver a held change's full reload when its block clears

A clean save, Use external and Keep Studio now all deliver the merged scope a blocked change owes, and a moved-in .hyperframes folder reports its manifests so a dropped one still clears the cached signature.

* fix(studio): keep restored drafts out of the reload scope and clear the lint gates

* fix(studio): retain held reload scope before React renders
2026-10-07 07:32:16 +00:00
Miguel Ángel 4fcad1ed74 fix(media-use): use a host app's music tools; fail loudly without the heygen CLI (#5154)
* fix(media-use): use a host app's music tools; fail loudly without the heygen CLI

* fix(media-use): name the heygen CLI only for music and sound effects; keep the sfx test offline

* fix(skills): workflow skills use a host app's own music tools first

* fix(skills): say how a host app's music track reaches the narrated workflows

* fix(skills): set a host app's music track after the last audio pass

* fix(skills): a host-music film with no narration still fetches its sound effects

* fix(media-use): keep the stub-failure test off the machine's heygen CLI; sync the skills manifest

* fix(skills): audio passes keep a host app's music and sounds; silent needs no sound cues

* fix(skills): host audio keeps string frames, stops on a broken audio_meta.json, survives a re-run

* fix(skills): report a host audio entry with no path and a broken sidecar instead of crashing

* fix(skills): keep host audio written while an audio pass runs

* test(cli): serve the telemetry capture while the resolve child waits on it

* test(cli): fail the telemetry capture when the resolve child exits non-zero

* style(skills): wrap the host audio comment to the 120-column limit
2026-10-07 07:16:51 +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 9e0d05d450 fix(engine): auto worker count stays within the heap budget (#5149)
* fix(engine): automatic worker count never exceeds what the V8 heap can feed

A 24 GB Mac exporting a 43 s portrait project with 22 videos picked 5 capture workers against a 4192 MB heap that feeds about 4, and the render died at 62% with JavaScript heap out of memory. The heap budget was only advisory; it now caps the automatic count (bound 'heap'). An explicit --workers N is untouched.

* test(engine): heap-cap test restores its mocks even when an assertion fails

Review findings on #5149: the os and v8 mocks were restored only if every assertion passed, and two comments still called the heap cap advisory.

* docs(engine): heap budget comments say it caps auto sizing
2026-10-07 06:11:30 +00:00
Miguel Ángel 9fbec22596 fix(cli): load telemetry without the core and engine barrels, and stop the history test racing (#5153)
* fix(cli): load telemetry without the core and engine barrels, and stop the history test racing

* fix(cli): load history from its leaf subpath, and fail the history test fast on a crashed CLI
2026-10-07 06:05:41 +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
Miguel Ángel cffc3aa4e1 feat(render): report encoding and assembling progress (#5137)
* feat(render): report encoding and assembling progress

* fix(render): close every progress stage and fail a render whose progress callback throws

* fix(render): send a repeated progress update once

* fix(render): keep Docker terminal output as before and drop the unneeded callback ending

* fix(render): keep one failure stage code per stage whatever its frame counts
2026-10-07 04:29:35 +00:00
Miguel Ángel 11e684d305 fix: the preview preloads the coming scene's images, and check stops failing on image swaps (#5128)
* fix(core): the preview loads the next scene's images before it starts

* fix(cli): check stops reporting image loads that its own scrubbing cancelled

* fix: preload only a coming clip's own images, and judge aborted images by whether they still decode

* fix(cli): count an aborted image as broken only when its decode fails

* style(cli): keep the aborted-image comment within the line limit

* test(cli): pin that a reload still pending at the cap is not reported

* test(cli): run the cap test on whatever timers are pending, and always restore real timers
2026-10-07 00:10:29 +00:00
Miguel Ángel e6daed3df0 chore: release v0.8.139 (#5136)
* chore: release v0.8.139

* chore: sharpen the v0.8.139 release summary
2026-10-07 00:06:22 +00:00
Miguel Ángel f7bba2288d fix(cli): read the WAV in JS so Built-in transcription runs inside Electron (#5129)
* fix(cli): read the WAV in JS so Built-in transcription runs inside Electron

* fix(cli): read an empty WAV as silence
2026-10-06 23:15:50 +00:00