Commit Graph
1809 Commits
Author SHA1 Message Date
Miguel Ángel bb9e507e84 perf(packages): ship npm packages without source maps and guard their size in CI (#5403)
* perf(packages): ship npm packages without source maps and guard their size in CI

No package or consumer reads the published source maps, so they are no
longer built. The CLI copies only the studio app it serves instead of the
whole studio dist. verify:packed-manifests now holds every published package
to a size budget that ratchets down, and CI rejects pull requests that add a
large binary outside LFS.

* fix(ci): large-binary check reads every filename and fails on git errors

* ci: run only Build when a skill bundled into the CLI changes

* fix(ci): size guards also catch type changes, odd file names, unreadable blobs and bad budgets

* fix(ci): large-binary check reads blobs by id and skips submodules

* fix(ci): exempt only exact registry copies under docs/public/catalog

* test(ci): cover the staged catalog-copy exemption; drop the local-only override hint in CI

* fix(ci): producer budget follows its slimmed package; size checks name their real cause
2026-10-10 09:04:47 +00:00
Miguel Ángel 165be85132 fix(cli): timeline split keeps a sub-composition's place in both halves (#5410) 2026-10-10 08:05:14 +00:00
Miguel Ángel 76f8a567a5 chore: release v0.8.145 (#5412) 2026-10-10 08:04:19 +00:00
Miguel Ángel 856967b25a fix(cli): list valid families when media-treatment gets an unknown capability (#5409)
* fix(cli): list valid families when media-treatment gets an unknown capability

* test(cli): the capability list test typechecks under strict index access

* fix(cli): the unknown capability error calls its list areas and claims only what holds

* fix(cli): the unknown capability error lists only the areas it accepts
2026-10-10 07:48:57 +00:00
Miguel Ángel affa4d53cf fix(producer): the npm package ships only its own code and no source maps (#5398)
* fix(producer): the npm package ships only producer's own code, without source maps

* fix(cli): the npm package leaves out Studio's source maps, like its own

* fix(producer): the published package finds its workers and pins its own packages exactly
2026-10-10 07:04:34 +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 91f9c9eb04 feat(studio): export can encode on the GPU, like render --gpu (#5397)
* feat(studio): export can encode on the GPU, like render --gpu

* test(studio): the 4K export assertion carries the GPU flag

* refactor(studio): the GPU flag needs no comment beyond its name

* fix(studio-server): only MP4 exports encode on the GPU, and render errors report it

* fix(studio): the disabled GPU option dims like the other export controls
2026-10-10 04:45:05 +00:00
Miguel Ángel 3d6de0581e fix(engine): audio duration probe reads to the end on Windows; cli tests skip bun's disk cache (#5395) 2026-10-10 03:05:46 +00:00
Miguel Ángel f8ee010c65 chore: release v0.8.144 (#5384) 2026-10-10 00:45:48 +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
Miguel Ángel f85614ecb2 fix(cli): WebGPU compositions work in snapshot, check and layout like render (#5354)
* fix(cli): snapshot, check, layout and thumbnails honour software WebGPU like render

* test(cli): stub the local WebGPU helper in the studio server tests

* fix(engine): webgpu compositions are recognised after the bundled runtime script

* fix(engine): a hung GPU probe falls back to software in 15 s instead of 120 s

* fix(engine): the GPU probe keeps the configured launch timeout and bounds only its page

* build(parsers): declare the html-attribute-spans subpath in its descriptor

* build(gcp-cloud-run): the BeginFrame contract stage copies parsers, which the engine now imports

* test(cli): the screenshot launch pin follows the shared local WebGPU helper

* fix(engine): the GPU probe's wait for Chrome's first page falls inside its 15 s limit
2026-10-10 00:08:07 +00:00
Miguel Ángel 908f4395b4 feat(cli): let transcribe --to write srt or vtt straight from a media file (#5215)
* feat(cli): let transcribe --to write srt or vtt straight from a media file

* fix(cli): fail a missing transcribe --output folder before decoding

* fix(cli): reject a transcribe --output that names a folder

* test(cli): check CJK caption grouping on the parsed cues

* fix(cli): keep transcribe --output from overwriting the media or its transcript

- Refuse an --output that resolves to the input file or the transcript.json the run writes,
  before the engine starts.
- When the caption file cannot be written after transcribing, say the transcript was saved
  and name the caption path and reason, instead of reporting a failed transcription.
- Docs: a one-run export groups cues for languages without spaces; exporting the saved
  transcript later may split them differently.

* fix(cli): refuse caption paths that alias the media or transcript

- The overwrite check compares files, not path text: an existing target is matched by device
  and inode, a new one by its real folder and its name ignoring letter case. Links, folder
  aliases such as /var and /private/var, and other letter case are all refused.
- The check also covers the default caption path, so exporting transcript.srt to srt no
  longer rewrites its own input.
- A trailing -o with no path fails before transcribing.
- One constant names transcript.json for the engines, the import and the check.

* fix(cli): refuse caption links to the transcript before it exists

- A caption path that is a link is followed to where the write would land, so a link to the
  transcript.json the run is about to create is refused before transcribing.
- A test pins the folder letter-case check on a case-insensitive disk, and says which branch ran.

* fix(cli): check the caption file against the transcript right before writing it

- Right before the caption write, by when the transcript exists, a destination that is the
  same file as the input or transcript.json is refused. The OS resolves every link, relative
  link and alias, so the hand-written link following is gone.
- The run keeps the transcript and says the caption file could not be written and why.
  An export whose caption write fails now says so too, instead of crashing.
- The check before transcribing stays as an early refusal for the common cases.

* fix(cli): compare caption paths by name when the disk reports no inode

- Some network shares report inode 0 for every file; such a pair is compared by folder and
  name instead of being called the same file. The check before transcribing and the one at
  write time now share one comparison.
- The link-through-a-file tests accept ENOENT as well as ENOTDIR, the code Windows reports.

* fix(cli): resolve both caption paths fully when the disk reports inode 0

- When either file reports inode 0 and both exist, compare their fully resolved real paths,
  so a link to the media or the transcript is still refused. The folder and name compare
  stays for a path that does not exist yet.
- Tests zero the inode on every path, on the caption path only, or on the protected file only.

* test(cli): say plainly why the caption-write test accepts two error codes
2026-10-09 22:54:36 +00:00
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