Commit Graph

4211 Commits

Author SHA1 Message Date
heygen-rui-bot 3539d72ddf codegen: resync cloud client from EF 65ee22fc 2026-09-08 03:06:08 +03:00
blw dc9fb67320 fix(slideshow): retry init at DOMContentLoaded when the children were not parsed yet (#3750)
connectedCallback defers init to a setTimeout(0) so the parser can append
the element's children first. With the bundle loaded from <head>, as
`hyperframes present` emits it, headless Chromium fires that timer while
the parser is still inside <hyperframes-slideshow>: init finds no player
or a half-streamed island, returns, and the deck never binds.

While document.readyState is "loading", init now retries once at
DOMContentLoaded. After parsing there is nothing to wait for, so a missing
or malformed island still fails quietly as before. The subtree check is
split out as locateSlideshowParts so the classification is testable
without the element lifecycle.
2026-09-07 16:03:16 -04:00
James Russo bb89f7507d docs(changelog): weekly digest 2026-08-31–2026-09-07 (#3749)
* docs(changelog): weekly digest 2026-08-31–2026-09-07

Rewritten from the 111 non-merge commits in the window, grouped by theme.
The week was mostly hardening: file reads pinned to checked descriptors,
bounded parser scans, and isolated concurrent writes. Studio agent control
and site capture continued.

Every commit sha and PR number was resolved and verified against the repo,
not hand-typed.

— Rames

* docs(changelog): add weekly changelog video for 2026-08-31–2026-09-07

Embeds the rendered 49.5s digest video. Uploaded to
static.heygen.ai/hyperframes/changelog-videos/weekly-changelog-aug31-sep07.mp4
and verified live before committing the src (200, content-length matches the
object, cache miss).

— Rames Jusso
2026-09-07 15:56:02 -04:00
James Russo b9aae16d6d fix(producer): try Windows junctions before copying cached frames (#3740)
Follow up Anton Sidorov’s junction staging contribution in #2314 on current main.

Co-authored-by: Anton Sidorov aka anticodeguy <a@anticodeguy.com>
2026-09-07 15:52:24 -04:00
Miguel Ángel 30d6f43bdb chore: release v0.8.31 (#3747)
* chore: release v0.8.31

* docs(release): describe the range fix on its own terms
v0.8.31
2026-09-07 12:12:35 -04:00
Miguel Ángel 8958342dd1 fix(studio-server): bridge the node web stream type for the Windows build (#3746)
tsc on the Windows jobs rejects a direct cast from node:stream/web's
ReadableStream to the global one (TS2352), which broke the build after
#3745. Cast through unknown, the bridge the error itself recommends.
2026-09-07 10:57:58 -04:00
Miguel Ángel 8825def610 fix(studio-server): stream preview media byte ranges instead of reading the whole file (#3745)
The Studio preview asset route answered every Range request by reading the
entire file into memory with readFileSync and slicing the window out of the
buffer. A browser refills a playing <video> or <audio> with a fresh Range
request every few hundred milliseconds and issues one per seek, so a source
of a few hundred MB cost a full synchronous read per refill and per scrub
step. The read also blocked the event loop, so the voice track, saves and
the file-change stream all waited behind it. Sources over 2 GiB could not
be served at all, because readFileSync refuses them.

Stream only the requested window with createReadStream, take the size from
stat instead of the buffer, and answer 416 for a range that starts past the
end. Text assets keep the in-memory utf-8 round trip. The sibling static
project server already did this.
2026-09-07 10:55:54 -04:00
Xuanru Li 0d5d3f3eb3 feat(lint): flag video/img src pointing at an audio file (#3741)
* feat(lint): flag video/img src pointing at an audio file

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

* refactor(lint): drop m4a from the audio src kinds

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 19:08:51 -07:00
Xuanru Li b0ac581d8e fix(lint): see the grouped gsap.set that stages a whole scene at once (#3737)
Hiding several elements in one call is the shortest way to stage a scene, and it was
the one form the hidden-selector extractor could not read: a multi-element array
failed the target regex, which forbade commas, and a single-element array then failed
the selector parse, which accepted only a quoted string or a known alias. So the two
error rules that ask whether a hidden element is ever properly revealed had an empty
hidden set for every grouped hide.

Each part of a group now resolves on its own, and a comma-separated selector string
resolves the same way. The target pattern stays paren-free so a set whose vars are a
variable cannot run past its own closing paren and swallow the next call.

Two false positives the wider hidden set exposed in the fullscreen-overlay rule: a
fromTo at 0 seats its from-vars immediately, so hidden from-vars there mean the
overlay does start hidden; and an overlay hidden by a standalone gsap.set is what
that rule's own fixHint prescribes.
2026-09-06 19:00:33 -07:00
Xuanru Li c59fd162aa fix(check): key content_overlap and text_occluded collapse by pair, and bill a clipped text box once (#2801)
Combines two fixes to the layout audit:

- `staticIssueKey` no longer includes `issue.text` for `content_overlap`
  and `text_occluded`; both builders now emit a unique selector for both
  ends, so the selector pair is the identity. An animating subject
  (count-up, typewriter, rotating word) no longer splits one held
  collision into transient groups.
- A clipping box that is its own nearest constraint reports
  `clipped_text` only, instead of also reporting `text_box_overflow`.
  A non-clipping self-constraint still reports.
2026-09-06 18:54:18 -07:00
Xuanru Li 051336c07b fix(lint): stop three rules matching code a composition only displays (#2811)
A code-explainer composition renders selectors and API calls as text.
`stripJsStringLiterals` blanks string and template contents (offsets
preserved) so `composition_id_selector_in_comment`,
`template_literal_selector` and `raf_animation_loop` scan real code only.

The scanner tracks regex-vs-division context so a regex literal's own
quotes cannot open a phantom string and blank the rest of the script; on
any unbalanced scan it returns the source unchanged, so an unmodelled
parse degrades to the pre-existing behaviour rather than blanking code on
an error-severity gate.
2026-09-06 18:34:02 -07:00
Xuanru Li 39ad2721b3 fix(check): keep auditing when a motion spec is partly unusable (#2805)
Combines two fixes to the motion sidecar path:

- An ambiguous selector no longer aborts the whole spec. It is reported
  as a finding, the assertions that depend on it are skipped and named,
  and every other assertion still evaluates. `assertionTargets` is now
  exhaustive over the assertion kinds so a new kind cannot silently fall
  back to an arbitrary first match.
- A sidecar that will not parse is reported as a spec finding instead of
  ending the run, so the composition is still audited.
2026-09-06 18:02:21 -07:00
James Russo 7a2a691736 fix(catalog): bind asset reads to checked project files (#3735)
* fix(catalog): bind asset reads to checked project files

* fix(catalog): budget the exact bytes published

* fix(catalog): bound directory asset reads
2026-09-06 01:18:16 -04:00
James Russo f1d0c2e553 fix(producer): pin lint entry reads to checked descriptors (#3734)
* fix(producer): pin lint entry reads to checked descriptors

* test(producer): replace lint entry paths portably
2026-09-06 00:12:41 -04:00
James Russo e5b3514118 fix(studio-server): publish waveform caches atomically (#3731)
* fix(studio-server): publish waveform caches atomically

* fix(studio-server): reject linked waveform cache directories
2026-09-05 23:21:36 -04:00
Miguel Ángel 3874990449 chore: release v0.8.30 (#3733) v0.8.30 2026-09-05 23:14:12 -04:00
Miguel Ángel 672ea844a5 fix(cli): clarify publish visibility and claim links (#3730)
* fix(cli): clarify publish visibility and claim links

* style(cli): apply oxfmt to publish visibility test

* chore(skills): regenerate skills manifest for updated references

* fix(cli): stop an in-place re-publish claiming it made the project private

* test(cli): pin in-place visibility copy to the plain re-publish route
2026-09-05 23:10:42 -04:00
Miguel Ángel 1fa31d5dfb feat(cli): keep every icon a site declares and headline the bare mark (#3727)
A brand band shows logo artwork on a transparency checker, where a badge (a
mark knocked out of a full-bleed disc or square) reads as a solid blob. The
capture kept only the first icon that downloaded, so which of a site's icons
survived was decided by ranking alone, and nothing recorded what the survivor
actually looked like.

Keep them all. Each declared icon is written as assets/icon-<rel>-<sizes>.<ext>
and classified as bare-mark, badge, or unknown, then the best one is copied onto
the historical assets/favicon.<ext> stem so a stem match still finds it.

Classification is deterministic and cheap. SVG is read from markup, not
rendered: these files routinely fill via CSS custom properties behind a
prefers-color-scheme query, and librsvg resolves neither, rasterising one real
favicon to a fully transparent image while Chrome draws it correctly. Raster
icons are sampled at the midpoint of each edge rather than the corners, because
a full-bleed disc has four transparent corners and would otherwise read as a
bare mark.

The headline prefers a bare mark, then falls back to the existing ranking.
Preference is binary on purpose: an "unknown" is not promoted above a badge,
or an undecodable .ico would outrank a good SVG purely for being unexaminable.

extracted/icons-manifest.json records every icon, its shape and the evidence
for that shape, plus which file became the headline, its rank, and why. A
choice whose losers are invisible is indistinguishable from having had no
choice, which is how a substituted icon went unnoticed in the first place.

Worth noting for consumers: sites often declare no bare mark at all. An
apple-touch-icon is composited onto an opaque tile per Apple's spec, so it is
a badge, not a mark. The manifest says so rather than implying the preference
was satisfied.
2026-09-05 22:35:45 -04:00
James Russo 97fde27df7 fix(cli): pin Studio bundle, signature and runtime file reads (#3728)
* fix(cli): read Studio bundle files through checked descriptors

* fix(cli): pin Studio signature and runtime artifact reads
2026-09-05 22:23:15 -04:00
Miguel Ángel 7a07ea9ac3 fix(cli): fetch a page's assets as the same agent that loaded the page (#3726)
A capture is one session with two halves: Chrome navigates the page with a
browser User-Agent, then Node fetches the assets that page referenced. Those
halves sent three different identities — "HyperFrames/1.0" from the asset and
media downloaders, a bare "Mozilla/5.0" from the stylesheet inliner, and the
real Chrome UA from the navigation itself.

An origin is free to answer those differently, and anti-bot edges do. Capturing
one large site, GET /favicon.svg answers 403 text/html to "HyperFrames/1.0" and
200 image/svg+xml to the UA the very same capture had just navigated with. The
favicon ranker had already picked that SVG as the best declared icon; the 403
discarded it and the downloader fell through to the next candidate, so the icon
written to assets/ was chosen by the CDN's bot rules rather than by the ranker.
The capture reported it as one "unavailable" drop and carried on.

Hoist the navigation UA into CAPTURE_USER_AGENT and use it for every
out-of-band fetch the capture makes: favicons, images, og:image, fonts,
stylesheets, Lottie JSON and videos. One constant is what stops the two halves
drifting apart again.

Verified end to end against that site: before, assets/favicon.png (the
apple-touch icon) plus one unavailable drop; after, assets/favicon.svg, byte
identical to the file the site itself serves.
2026-09-05 22:20:15 -04:00
James Russo be86a1ec7d fix(render): serve engine and producer files through checked descriptors (#3725)
* fix(engine): read served files through checked descriptors

* fix(producer): retain checked files through streamed responses
2026-09-05 21:38:42 -04:00
James Russo 41551c7acb fix(cli): read caption images through checked file descriptors (#3724) 2026-09-05 20:43:36 -04:00
James Russo cfdaccb7e6 fix(cli): publish cached synthesis script exclusively (#3722) 2026-09-05 20:05:15 -04:00
James Russo b49fba8dea fix(cli): preserve concurrent scaffold config creation (#3721)
* fix(cli): preserve concurrent package metadata during init

* fix(cli): preserve concurrent project config creation
2026-09-05 19:35:41 -04:00
James Russo e6d2816e1d fix(cli): publish capture metadata without overwriting files (#3720)
* fix(cli): create capture metadata exclusively

* fix(cli): publish capture metadata without following links
2026-09-05 18:47:53 -04:00
James Russo b94b5bde58 fix(core): bound timing compiler opening tag scans (#3719)
* fix(core): bound timing compiler opening tag scans

* fix(core): bound ID-targeted duration tag scans
2026-09-05 18:02:36 -04:00
James Russo 3610d94a98 fix(producer): bound existing font-face recognition scans (#3718) 2026-09-05 17:17:33 -04:00
James Russo e78da303f4 fix(core): bound inert region scans in timing compiler (#3717)
* fix(core): bound inert region scans in timing compiler

* fix(core): use literal search for comment terminators

* fix(core): recognize end-bang HTML comment boundaries
2026-09-05 16:40:39 -04:00
James Russo fe2cc92050 fix(studio-server): bound preview variable insertion scans (#3715)
* fix(studio-server): bound preview variable insertion scans

* docs(studio-server): update preview variables helper reference
2026-09-05 15:32:34 -04:00
James Russo 7d7003aa64 fix(studio): match style attributes with explicit quote boundaries (#3712)
* fix(studio): match style attributes with explicit quote boundaries

* fix(studio): apply quote boundaries to active source writers
2026-09-05 14:50:27 -04:00
James Russo e9250fcc45 fix(studio-server): simplify normalized group ID trimming (#3711) 2026-09-05 14:12:24 -04:00
James Russo 51a3c7e245 fix(engine): isolate WAV staging in a private directory (#3709)
* fix(engine): create WAV staging files exclusively

* fix(engine): isolate WAV staging in a private directory
2026-09-05 13:44:44 -04:00
James Russo c564daf210 fix(studio): avoid inline style regex backtracking (#3708) 2026-09-05 12:58:26 -04:00
James Russo eec04340b3 fix(core): avoid grade stats regex backtracking (#3706) 2026-09-05 12:28:59 -04:00
James Russo e5d1d9bf0e fix(engine): avoid transform regex backtracking (#3704) 2026-09-05 11:53:43 -04:00
James Russo f13037ecd4 fix(engine): isolate chunked encode temporary files (#3680) 2026-09-05 11:15:46 -04:00
miga-heygen ae3d80c30f chore: release v0.8.29 (#3690) v0.8.29 2026-09-04 21:50:46 -04:00
miga-heygen 00c575d23b fix(studio): prevent preview hang on burst external file rewrites (#3648)
* fix(studio): prevent preview hang on burst external file rewrites

Two interacting bugs caused Studio to freeze when multiple processes
(generator, check, snapshot) burst-wrote index.html within seconds:

1. SSE listener leak: the /api/events handler added a watcher listener
   per client connection but never removed it on disconnect. Reconnects
   accumulated dead listeners, each triggering readFileSync on every
   file change and writing to closed streams.

2. Generation starvation: processChange incremented generationRef and
   awaited drainPendingChanges. A second event arriving mid-drain bumped
   the generation, causing the first drain to bail at the generation
   check. With rapid writes, no drain ever completed and Studio stayed
   frozen on stale content.

Fix 1: use stream.onAbort() to remove the watcher listener when the
SSE connection closes.

Fix 2: gate processChange with a draining ref. While a drain is in
progress, stash the latest event. On completion, process the stashed
event — the last write in a burst always completes its reload.

Closes #3646

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

* fix(studio): align coordinator tests with drain serialization

Update existing test to expect the new behavior: when two events
fire in quick succession, the first drain completes and triggers a
reload (previously it was silently discarded). The stashed event
then starts a second drain.

Also fix the burst-write test to use the drains array pattern and
explicit act() flushes for stashed event processing.

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

* fix(studio): stash events with allowDuplicate and harden listener cleanup

Address Rames's review findings:

- Stash with allowDuplicate: true so re-dispatched events are not
  swallowed by the duplicate guard (the identity was already written
  on the way in, so the stashed event matched itself on re-entry).
- Wrap SSE keepalive loop in try/finally so the listener is removed on
  both abort and throw, not just abort.
- Restore stale-completion guard test coverage lost in the rename.
- Use await act(async () => {...}) for burst dispatches so assertions
  depend on the stash guard rather than scheduling.

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

* fix(studio): simplify drain serialization and restore SSE cleanup

Restructure processChange into intake + drain loop:

- processChange is now synchronous — validates, dedupes, checks own
  echoes, enqueues the accepted payload, and starts the drain loop
- startDrainLoop runs while the pending slot is non-null, draining
  one event per iteration via drainOnePending
- No recursive void processChange(...) from finally, so no
  allowDuplicate escape hatch needed — stashed events never re-enter
  intake guards

SSE listener: restore stream.onAbort alongside try/finally. Hono's
sleep() never throws, so finally alone doesn't fire on disconnect.
Both paths call removeListener (Set.delete is idempotent).

Tests: remove stale-drain test that contaminated subsequent tests by
emptying the shared roots array mid-test. Use sync act() for burst
dispatches — the stash decision is synchronous.

All 10 coordinator tests pass locally (NODE_ENV=test).

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-09-04 21:44:25 -04:00
Miguel Ángel 64ce9fdf1f chore: release v0.8.28 (#3689) v0.8.28 2026-09-04 21:01:08 -04:00
James Russo 9ed50028c4 fix(capture): sample computed shadows on ordinary boxes (#3686)
Co-authored-by: Xuanru Li <157947275+xuanruli@users.noreply.github.com>
2026-09-04 20:28:17 -04:00
James Russo a7cdd583e7 fix(capture): retain opaque and glass button styles (#3685)
Refresh the capture fixes proposed in #1880 with browser-backed regression coverage.

Co-authored-by: Xuanru Li <157947275+xuanruli@users.noreply.github.com>
2026-09-04 20:28:07 -04:00
James Russo 65cf87de38 fix(core): scope composition root pattern selectors per instance (#3684)
Port the authored-root selector fix from Thomaswebstich in #2262 to current main.

Co-authored-by: Thomaswebstich <thomas.schnerb@gmail.com>
2026-09-04 20:27:56 -04:00
James Russo 19dee4cede fix(render): serve media assets with registered content types (#3677)
Port the MIME mappings reported by fix2015 in #1836 to both render file servers.

Co-authored-by: vitalii.semianchuk <fix20152@gmail.com>
2026-09-04 19:54:29 -04:00
James Russo 7fcb5be6ea docs(registry): clarify catalog preview staging and published URLs (#3676)
Co-authored-by: yoma <yingwaizhiying@gmail.com>
2026-09-04 19:53:18 -04:00
James Russo 1f9f86c857 docs(studio): align stack note with package dependency contract (#3675)
Co-authored-by: yoma <yingwaizhiying@gmail.com>
2026-09-04 19:53:07 -04:00
James Russo 44208ceada docs(cli): document current publish workflow (#3674)
Refresh the README guidance from #1950 for current auth, visibility and updates.

Co-authored-by: yoma <yingwaizhiying@gmail.com>
2026-09-04 19:52:54 -04:00
James Russo 893141413e docs(core): fix published frame adapter reference links (#3667)
Co-authored-by: yoma <yingwaizhiying@gmail.com>
2026-09-04 19:30:59 -04:00
James Russo 36ec028d5f fix(cli): forward GIF and frame-format options in batch renders (#3666)
Port Dustin Persek’s fix and command regression from #1833 onto current main.

Co-authored-by: Dustin Persek <dustin.persek@protonmail.com>
2026-09-04 19:30:50 -04:00
James Russo 66052255cf fix(producer): isolate font cache temporary writes (#3669) 2026-09-04 19:30:47 -04:00
James Russo a93106aebf docs(skills): fix creative house style reference links (#3668)
Co-authored-by: yoma <yingwaizhiying@gmail.com>
2026-09-04 19:19:25 -04:00