Repository navigation
fix(cli): bug-bash fixes for pull, offline, preview, check, cloud aspect, sfx search, and media-use avatars - #7170
Conversation
Unpacking now runs tar asynchronously and removes its .part folder on SIGINT/SIGTERM/SIGHUP before re-raising the signal. Part folders carry the owning pid, and the next pull clears any whose process is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ached Offline, both commands waited on unbounded requests and then printed only undici's 'fetch failed'. A new networkFailure helper names the host, the reason (DNS lookup, no route, refused, no answer in time, dropped) and the next step. The account and token-refresh requests now time out after 15 s, the template link after 15 s, and auth status reports an offline refresh at once instead of retrying with the stale token. describeCauseChain moves into the helper so the registry and auth share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a project in preview stamped data-hf-id into every composition on disk. The preview route and every source mutation already mint the same content-keyed ids in memory, so the startup pass is dropped: files gain ids only when an edit to them is saved. The .hyperframes folder is still made before the watcher starts, so the preview cache creating it is not reported to Studio as a manifest change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A lint error made check skip runtime, layout, motion and contrast, so one known lint error hid every browser finding. The browser pass now runs whenever there is a composition to load, and the lint error still fails the check. Only a root with no data-composition-id skips it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 'Keep editing by chatting with Framey' line printed on every render and preview, including CI and piped runs where nobody can open the app. It now prints for a person at a terminal, and for a coding agent, which the hyperframes skill tells to pass the line on; CI and other non-TTY runs get nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A 1920x960 composition got 'server will default aspect_ratio to 16:9' although the render kept 1920x960: at 1080p the cloud renders at the composition's own size and aspect_ratio only picks a 4K preset. The CLI now names the detected ratio (2:1) and says the size is kept, takes --aspect-ratio as any W:H checked against the composition, sends only the 16:9, 9:16 and 1:1 the API accepts, and refuses a 4K render of any other ratio before upload, where no preset fits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…silently
resolve --type sfx returned a HeyGen sound at any score down to 0.4, and a
project file that shared one word of its name with the intent, with nothing
to tell them from a real match. Such a result now carries a match object in
the JSON ({score, min_score, low_confidence} or the matched words and the
intent the file was resolved for) and a low-confidence line on stderr. A
HeyGen search with no hit says so with the min score it used, and a sound
effect nothing matches fails with 'no sound effect matched'.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Templates had to reach for 'heygen avatar list', a separate sign-in that can
be another account. 'media-use avatars' lists the private looks on the
HyperFrames account making the film (GET /v3/avatars/looks?ownership=private,
following next_token up to --limit) as {avatars: [{avatar_id, name, ...}]},
the id that 'generate --type avatar --avatar' takes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
…s that skill Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jrusso1020
left a comment
There was a problem hiding this comment.
Changes requested. Reviewed at 20619362e98db3467133684925ef923a28322bd1, including the two-file description/manifest delta from requested a13908c50429997f5c45c3c26ee6192598ed3ddb. Miao re-pinned this revision as ready during review.
Important — abandoned-part cleanup deletes unrelated user files (packages/cli/src/commands/templates.ts:143–152). removeAbandonedParts() removes every sibling starting <slug>.part- unless its next token happens to be a live PID. Pulling sample deleted my templates/sample.part-notes/my-notes.txt, sample.part-reference.txt, and a sibling symlink, then successfully installed the template. A prefix and a dead/unparseable PID do not establish ownership. Restrict cleanup to positively identified CLI-owned temporary directories (strict generated name plus an ownership marker); preserve unknown files/directories/symlinks and unmarked legacy entries. Add preservation tests alongside the abandoned-pull case. Repro used the real pullTemplate and real local tar, with only fetch stubbed: unrelatedDirectorySurvived:false, unrelatedFileSurvived:false, unrelatedSymlinkSurvived:false, templateInstalled:true; the external symlink target survived.
Nit — retain offline recovery when avatar credential refresh fails (packages/cli/src/heygen/avatars.ts:75–77). This catch changes a refresh NetworkFailure into “no HeyGen sign-in” / auth login, although the stored login can still exist. Convert it to Fix(error.message, error.hint) as fetchPage does; reserve login recovery for actual credential failures. The shared resolver is correctly the same HyperFrames chain used for film generation, not the separate HeyGen CLI store; API-key and OAuth/host-token precedence remain that resolver's policy.
Nit — confidence metadata disappears on reuse (packages/cli/src/media-use/resolve.mjs:361–363,580–616). The first weak provider/name match gets match, but it is not stored on the record and exact-prompt cache hits call result() without it. Preserve/reconstruct the advisory from provenance and test a second identical resolve. Asset selection itself is unchanged, so this is a follow-up.
Validation: bun run build and bun packages/cli/scripts/gen-skills-manifest.ts --check passed. At a13908c, the nine focused CLI suites passed 272 tests (214 preview/cloud/check/desktop in the independent pass; 58 template/avatar/auth/network here), and the resolve engine reported 67 passed / 0 failed. Those code/test paths are identical at this reviewed successor; only the style guide sentence and its generated hash changed. The independent real-tar preservation probe reproduces the Important issue. No live sign-in, paid render, cloud render or packaged Desktop walk was performed.
Audited: new avatar/network modules and template unpack/cleanup; credential refresh integration; cloud aspect submit logic, check continuation, preview-ID lifecycle and SFX reuse paths; changed tests/docs. Trusting: unchanged bulk command/server/check/resolve machinery outside these integration paths. Preview still mints IDs in memory; edit paths persist them. Executed preview tests cover untouched source and first element save; GSAP save behavior was source-traced against existing tests. I did not exercise repeated saves/reopen or concurrent editor changes.
No existing review or inline finding was present at acquisition; this is the first review round.
Cloud contract: source-read EF master c1dcf19e1e73924e609903f162b1d24e5f00ca2b: request DTO permits only 16:9/9:16/1:1, which this CLI respects by omitting other ratios. hyperframes_api_render.py:867–872 and hyperframes_render_parameters.py:1–5 forward supersampling only for *-4k; 1080p leaves native composition dimensions. This is source verification, not a deployed-image/paid-render claim.
Need: yes · Size: reviewable, eight independent fixes across 36 files · Reuse: shared HyperFrames credentials and network-cause helper · Simpler: cleanup must prove ownership before deleting · Structure: fine
Risk: medium — new recursive cleanup can remove user data.
Verdict: REQUEST CHANGES
Reasoning: Preserve unrelated sibling entries during cleanup. The remaining notes are nonblocking.
— hf-review
| if (!name.startsWith(partPrefix(dest))) continue; | ||
| const pid = Number(name.slice(partPrefix(dest).length).split("-")[0]); | ||
| if (Number.isInteger(pid) && pid > 0 && processIsAlive(pid)) continue; | ||
| rmSync(join(parent, name), { recursive: true, force: true }); |
There was a problem hiding this comment.
Important — user-data deletion. Prefix matching is not ownership: a real pullTemplate("sample", dir) removed my unrelated templates/sample.part-notes/my-notes.txt, sibling sample.part-reference.txt, and a prefix-matching symlink before successfully installing the template. Their suffix is not a PID, so they fall into recursive deletion. Please remove only positively identified CLI-owned temporary directories (exact generated naming plus ownership evidence), preserve unknown/unmarked siblings including files and symlinks, and add these preservation regressions. Keep live pulls protected.
There was a problem hiding this comment.
Fixed in 23d3f70 (head bb849a43). Each pull writes .hyperframes-pull.json (owner tag + pid) into its own part folder when it creates it. Cleanup removes an entry only if it is a real directory (not a symlink), its name matches the generated <slug>.part-<pid>-XXXXXX exactly, its marker has the owner tag and the same pid, and that pid is dead. Everything else is left alone: your files, folders and symlinks, unmarked folders, and legacy part folders. a9531be reads the marker through one O_NOFOLLOW descriptor and takes entry types from readdir, so there is no check-then-use. The tests use the real pullTemplate and tar: sample.part-notes/my-notes.txt, sample.part-reference.txt, an unmarked legacy folder, an unmarked dead-pid name, and a generated-name symlink to a marked outside folder all survive, as does its target. They fail without the fix.
Edit accuracy: accurate 267 (base branch 267), smooth 122 of thoseThe gate passes. Quarantined, measured but not gated (8)
Unstable (1)
|
…ts own The abandoned-part cleanup deleted any sibling named '<slug>.part-*' whose next token was not a live pid, so a person's own 'sample.part-notes/', 'sample.part-reference.txt' or a symlink went with it. A pull now writes an ownership marker (owner tag + pid) into its part folder, and the cleanup removes only a real directory with the generated '<slug>.part-<pid>-XXXXXX' name whose marker names a dead pid. Files, symlinks, unmarked folders and older unmarked parts are left alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cannot reach HeyGen A network failure while refreshing the stored login was reported as 'no HeyGen sign-in' with 'auth login' as the fix, though the login was still there. It now keeps the network failure's message and next step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first resolve of a weak HeyGen sound or a name-matched project file flagged it, but an identical second resolve hit the project manifest and returned it with no match object. The advisory is now rebuilt from the record's provenance (the stored score, or the adopted file's name) on reuse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om rising Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r written to disk CodeQL flagged the downloaded bundle written to a file before tar read it, and a stat-then-read in the preview test. The verified archive now streams into tar's stdin, so no network bytes reach a file the CLI writes. The abandoned-part scan takes the entry type from readdir instead of an lstat, reads the ownership marker through one O_NOFOLLOW descriptor it fstats, and the preview test reads each file once instead of stat-checking it first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed size main's @hyperframes/cli was already about 0.99% over its 23722874-byte unpacked budget, so this branch's additions (networkFailure, the avatars command, the larger skill references) tip it past the 1% tolerance. This is the same value #7169 sets, 25159107 bytes (5% headroom over the measured size), so the two PRs merge cleanly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck and font-lint additions Main's CLI unpacked size was already ~0.99% over its budget; the render lock and owner markers push it past the 1% tolerance. The CLI unpacked budget takes the same value as #7169 and #7170 (25,159,107) so the PRs merge cleanly. The engine's packed size grows by about 4.7 KB for the effect-scan and session-open watchdogs; its packed budget moves to 5% above the measured 467,097, as the budget file's headroom rule sets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
At ready head bb849a43, the earlier template-cleanup user-data deletion appears repaired: the reaper now requires a real directory with an exact generated name and a matching CLI-owned marker/dead PID, and the avatar-refresh/cache-confidence fixes have focused tests. Rames's original change request is still a separate gate. I found one remaining custom-aspect correctness failure in this PR's new 4K path (inline): a noncanonical authored ratio within the inherited 0.05 detector tolerance is returned as a supported 16:9 preset and skips the new pre-upload custom-ratio refusal. A 1920×1055 composition is a concrete input. Current-head Fallow audit also failed on pullOwner complexity and duplicate OAuth blocks; other hosted checks were still running, so this is not a green-CI claim. The CodeQL warnings on the earlier head were addressed by streaming the archive to tar and removing check-then-use in the test/marker path, but no cloud render or paid path was exercised by me. No merge or queue action. — Jerrai
| ); | ||
| failCommand(); | ||
| } | ||
| if (detection.kind === "matched") { |
There was a problem hiding this comment.
The detector's inherited ±0.05 band treats a custom 1920×1055 composition (ratio 1.8199, ≈0.042 from 16:9) as matched:16:9, so this new branch returns that preset and bypasses refuseUnsupportedAt4k. A cloud render --resolution 4k then sends aspect_ratio:16:9 for a composition that is not authored at 16:9, contrary to the new 'custom ratios refused before upload at 4k' contract. Please compare exact authored dimensions against a valid 4K preset (e.g. integer cross-products), or explicitly reject tolerated-but-noncanonical dimensions for 4K; add a near-preset custom-ratio regression.
There was a problem hiding this comment.
Fixed in c17dc90. A 4k cloud render now runs the producer's own checkOutputResolutionCompatibility (from @hyperframes/core) before upload, on the composition's exact size against the 4K preset the API would pick (landscape-4k / portrait-4k / square-4k). The ±0.05 band now only chooses which preset to ask for; whether it fits is the producer's exact check, run locally. An incompatible size is refused with the producer's reason and a 1080p or exact-size suggestion. Tests: 1920×1055, 1000×980 and 1055×1920 are refused at 4k (they fail without the fix), 1920×1080 / 1080×1920 / 1080×1080 are still sent as 16:9 / 9:16 / 1:1, and 1080p keeps 1920×1055 at its own size.
…nt POST Fallow flagged pullOwner (CRAP 49.5, cyclomatic 13) and a 28-line clone between refreshOnce and exchangeCodeForTokens. pullOwner is now the name match, the O_NOFOLLOW marker read and the marker check as three small functions, with the same behaviour. Both token requests go through one postToTokenEndpoint, which keeps the 15 s timeout and the named network failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at 3d36d71b283ea426e2f7b4f65e93e79865c30f6e, including the complete delta from 20619362e98db3467133684925ef923a28322bd1.
My cleanup blocker is fixed: cleanup now requires a real, exactly named directory with a matching CLI owner marker and dead PID. The real-tar preservation probe now keeps the original notes folder/reference file, unmarked/legacy entries, wrong-owner/PID markers, entry symlinks, marker symlinks and external targets, while removing a marked abandoned pull and retaining a live pull. Offline avatar refresh and repeated weak-match warnings are also fixed.
Important — Jerrai's near-preset 4K finding remains. packages/cli/src/commands/cloud/render.ts:492–494 still returns the detector's approximate preset before enforcing the custom-ratio refusal. Actual helper calls at this head accept 1920×1055 as 16:9 and 1000×980 as 1:1 for 4K; a true 2:1 input is refused. The producer's shared checkOutputResolutionCompatibility rejects both accepted near-preset examples as aspect-mismatch, so these inputs can pass the CLI's before-upload gate only to fail downstream.
Reuse that existing compatibility check for known local dimensions and the resolved 4K preset before returning/submitting, rather than treating the loose detector tolerance as compatibility. It also covers supersampling constraints. Add near-wide, near-square and near-tall negative controls alongside canonical successes. I am confirming the existing discussion with a second dimension class and the downstream predicate, without duplicating its inline.
Validation at this head: workspace build passed; template/avatar/OAuth/network suites passed 76 tests, resolve engine 67 passed/0 failed. Independent real-tar cleanup, repeated-cache advisory, aspect-selection and producer-compatibility probes passed their controls and reproduced the remaining aspect gap. No live sign-in, paid/cloud render or packaged Desktop run.
Scope: all 14 delta files and the affected caller paths; the unchanged preview-ID/check/desktop/cloud-auth surfaces retain my initial review scope and limitations. No additional introduced Important issue was verified.
Need: yes · Size: ok · Reuse: existing output-resolution compatibility predicate · Simpler: share the producer's precondition · Structure: fine
Risk: medium — unsupported 4K inputs reach the cloud instead of failing locally.
Verdict: REQUEST CHANGES
Reasoning: The cleanup and recovery/advisory fixes are sound, but the existing 4K compatibility blocker remains at this head.
— hf-review
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important (follow-up) · 0 nits · head 3d36d71b
Rames's three findings are fixed. The cleanup only removes exactly-named, marked part folders whose pid is dead; avatar refresh stays offline-aware; and a reused weak sound keeps its warning. CI is green at this head.
- Follow-up for Jerrai's open 4K thread (
render.ts:492), not a blocker. The ±0.05 match predates this PR: main also sent16:9at 4K for 1920×1055. The server doesn't letterbox it; the producer'scheckOutputResolutionCompatibilitythrowsaspect-mismatchafter upload. An exact 16:9 at a non-integer scale (1440×810) throwsnon-integer-scalethe same way. Running that check against the chosen preset before upload at 4K would close both. Until then, "4k needs 16:9, 9:16 or 1:1" is incomplete.
Scope
I read the changed source and tests end-to-end, then ran 219/219 tests across templates, cloud/render, networkFailure, check, auth and avatars. Also checked:
- Reaper races: the gap before the marker is written, pid reuse and own-pid all keep the folder (at worst a leak, never a deletion).
- Bundle install: the hash and byte count are checked before unpack, and the bundle is renamed into place only after a full unpack.
oauth.tsrefactor: a pure extraction; behaviour is unchanged.preview: no HTML writes are left on open.check: still exits 1 on a lint error.
I ran no paid, cloud or live sign-in path.
…before upload The aspect detector matches a ratio within ±0.05, so at 4k a 1920x1055 composition was sent as 16:9 and 1000x980 as 1:1, and the producer then refused both as an aspect mismatch. At 4k the matched ratio's preset (landscape-4k, portrait-4k, square-4k, the ones the API maps it to) now goes through the producer's own checkOutputResolutionCompatibility, and a composition it does not fit is refused locally with the producer's reason and the 1080p alternative. 1080p, where the render keeps the composition's own size, is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at c17dc902c4aea3c42c199d152191701dd81503b0, complete two-file delta from 3d36d71b.
The remaining 4K compatibility blocker is fixed. Known local dimensions now run the producer's shared checkOutputResolutionCompatibility against the actual landscape/portrait/square 4K preset before auth, archive preparation or upload. The approximate detector only selects a candidate; it no longer establishes compatibility. Explicit aspect-ratio flags cannot bypass the check.
Validation at this head: workspace build passed; the cloud-render suite passed 26/26. An independent adversarial probe passed 50 controls: near-wide/square/tall and non-integer upscales are refused; canonical ratios, integer 3× upscale and downsample pass; 1080p preserves native behavior. Actual CLI dry-run controls pass, and six nondry-run negative commands hit the compatibility error before auth/upload. No live account, paid/cloud render or packaged Desktop check was run.
The cleanup-preservation, offline avatar recovery and cached-confidence repairs are carried forward from my 3d36d71b review after confirming this two-file delta leaves them unchanged. No new substantive finding in this delta.
Need: yes · Size: ok · Reuse: producer's existing compatibility predicate · Simpler: one shared precondition · Structure: fine
Risk: low — local refusal now agrees with downstream constraints.
Verdict: APPROVE
Reasoning: The prior custom-ratio and adjacent non-integer-scale failures are stopped before upload while the tested valid and 1080p controls retain their behavior.
— hf-review
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Approved at c17dc902, superseding my prior 4K aspect-ratio change request. The CLI now uses the producer's own checkOutputResolutionCompatibility on exact composition dimensions and the chosen 4K preset before auth/upload; near-preset custom and non-integer upscale cases are refused, while exact presets pass and 1080p preserves native dimensions. I also verified the prior cleanup, avatar auth/offline and cached-confidence repairs in the composed head; Rames approved this exact revision. Hosted checks on this head report no failed or pending jobs at click time. No paid call, live cloud render, merge or queue action from me. — Jerrai
…t a time, and fonts the cloud can't resolve are flagged (heygen-com#7168) * fix(producer): a wedged effect scan or screenshot-session open trips the 60 s stall watchdog The sequential streaming watchdog raced only the capture call. Session init (where the fast-capture effect scan runs) and opening the screenshot session for effect frames waited on CDP's protocol timeout instead, which scales with output area up to 30 minutes, so a starved page hung a render for ~25 minutes before the watchdog saw the next frame. The effect scan now gives up when a chunk outlasts its 120 s budget, opening the effect-frame session gets its own no-progress window, and session init gets a 300 s one; each trip retries on a fresh session like any other stall. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): one local render at a time per machine; a second waits and says for whom Renders started side by side from different sessions starve each other until frames stop landing. `hyperframes render` now takes a machine-wide slot (a lock file in the HyperFrames cache directory, held by pid) after its preflight and holds it for the render or the whole batch. A second render waits and prints the pid and project it is waiting behind; `--no-wait` fails at once instead. A holder whose process is gone is taken over, and HYPERFRAMES_RENDER_LOCK=off restores side-by-side renders. `--workers` is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(lint): flag fonts a cloud render cannot resolve, including the font shorthand Lint read only `font-family`, so `font: 500 16px "PingFang SC", sans-serif` passed while the renderer, which reads the shorthand too, drew the installed Mac font locally and the cloud refused it. The shorthand now counts for font_family_without_font_face (its parser moves to @hyperframes/parsers so core and lint share one), and a new font_face_local_only warning names an @font-face whose only sources are local(): it renders here and falls back in the cloud. The rule's hint and the format reference stop recommending local() for OS fonts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): a cloud render that refuses a font says which project files use it The cloud's "fonts that could not be resolved: PingFang SC" named no composition. For a render submitted from a local project, the failure now lists each refused family with the project files that name it, and says how to ship the font so the cloud can use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(cli): keep comment shares and exports within the gates, and split the single-render notes out of executeHeldRender Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(parsers): read a spaced line-height slash and var() before the size in the font shorthand `font: 16px / 1.5 Inter` was read as the family `/ 1.5 Inter`, and `font: var(--weight) 16px Inter` as `16px Inter`, because a var() counted as the size. The parser now follows the shorthand grammar: optional style, variant, weight and width keywords (or var()), then a length, percentage, keyword or calc() size, then a `/ line-height` in any spacing. When no size can be told apart from a var(), it says so: lint skips that declaration instead of reporting a missing font, and the renderer keeps its best guess. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): say the render slot is one per user account, not per machine The lock lives in the account's HyperFrames cache folder, so renders by two user accounts never queued behind each other while the messages, flag help and docs said "this machine". They now say "per user account" and that HYPERFRAMES_CACHE_DIR set to a shared folder shares the slot across accounts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): reclaim a render lock or takeover file left half-written A lock or `.break` file that exists but cannot be parsed (a crash mid-write where hard links are unavailable) was never reclaimed: a waiting render waited forever and --no-wait refused forever. Once such a file is older than any real write (5 s by mtime) it counts as abandoned: the lock goes through the same `.break` takeover as a dead holder's, and a takeover file is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(producer): opening the capture session counts against the setup stall budget The sequential streaming attempt opened its own capture session (Chrome launch and new page) before the setup watchdog and outside the attempt's cleanup, so a wedged launch still waited for the protocol timeout. Opening now shares the 300 s setup window with session initialisation, a trip fails the attempt like any other sequential stall, and a session that finishes opening after its attempt gave up is closed instead of leaking a browser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(parsers): keep the shorthand result type module-private Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): reclaim an unreadable render lock only when its writer is provably gone Where hard links are unavailable the lock is created by an exclusive open and then written, so a contender paused between the two leaves an unreadable lock while it is still alive. The 5 s mtime grace took such a lock over, and both processes then held the slot. Each contender now writes an owner marker under a name only it can take (pid plus random suffix, holding its process identity) before it creates the lock, keeps it while it holds the slot, and removes it otherwise. An unreadable lock or `.break` is reclaimed only when no other contender's marker belongs to a live process; markers of dead processes, or of a reused pid, are deleted. No reclaim is decided by time alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor: split acquireRenderLock and the streaming-stage session stub under the complexity gate acquireRenderLock hands contender setup and a single marked claim to their own functions, and the test stub for createCaptureSession splits its held-open cases from the fake session it builds, so neither exceeds Fallow's cognitive or CRAP thresholds. Behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(ci): raise the CLI and engine size budgets for the watchdog, lock and font-lint additions Main's CLI unpacked size was already ~0.99% over its budget; the render lock and owner markers push it past the 1% tolerance. The CLI unpacked budget takes the same value as heygen-com#7169 and heygen-com#7170 (25,159,107) so the PRs merge cleanly. The engine's packed size grows by about 4.7 KB for the effect-scan and session-open watchdogs; its packed budget moves to 5% above the measured 467,097, as the budget file's headroom rule sets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(parsers): a var() size glued to its line height is the shorthand's size `font: 700 var(--size)/1.1 "Inter"` read as no family at all: the token was tested whole against var(), and the slash after it hid that it was the size, so the renderer injected no face for Inter. A var() followed by `/ line-height` (glued or spaced) can only be the size, and is now read as one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(parsers): split the shorthand size search out of parseFontShorthand Keeps parseFontShorthand under Fallow's cognitive-complexity gate; behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): render lock never removes another render's takeover, knows a reused pid, works in a shared folder and on Windows - A `.break` takeover file is removed only by the render that wrote it. One whose writer is gone stops the render with the file to delete, instead of being removed on an earlier reading, which could remove a live `.break` written since and let two renders hold the slot. The takeover re-reads the lock under its own `.break` right before replacing it. - The lock record keeps its holder's process start time, so a pid that now belongs to another process (an OOM-killed render in a container with a persisted cache) no longer holds the slot forever. - The `locks` folder is created writable for every account, so accounts sharing HYPERFRAMES_CACHE_DIR take turns instead of the second failing with EACCES; a folder this account cannot write in says how to fix it, and another account's file that cannot be removed is left, not fatal. - Windows: no PowerShell start-time lookup per check (pid liveness only), a file another handle holds (EPERM/EBUSY/EACCES) reads as held, a lock that vanished is retried once instead of in a tight loop, and a wait stops when its signal aborts. The tests end every acquire they start before removing their folder, and the paused contender writes through its open descriptor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(ci): raise the lint packed size budget for the font-shorthand rule With main's audio-attribute rule (heygen-com#7169) merged in, the font-shorthand and local()-only font findings take @hyperframes/lint's packed tarball to 181925 bytes, over the 179338 budget. The new budget is that measurement plus the usual 5% headroom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…licable heygen-com#7170 - heygen-com#7170 (applicable parts): CLI reports offline/network failures as NetworkFailure (host only) across auth, status, check and cloud render; registry reuses describeCauseChain; check pipeline and studio server stamp-on-open follow upstream. Desktop hint, SFX and templates/avatars parts deferred with prerequisites. - heygen-com#7148: X and Instagram links in docs. Watermarks: commit 06722eb, PR 7164, issue 7223; monitored 91. Co-authored-by: WaterrrForever <miao.yang@heygen.com> Co-authored-by: Ular Kimsanov <ularkimsanov7@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
CLI bugs from the style-sampling bug bash (Jake Moran's five-template run on 0.9.9, Miguel's checklist on 0.9.10):
templates pullno longer leaves atemplates/<slug>.part-*folder (bc3b2c4).auth statusandtemplates pullsay HeyGen can't be reached instead of waiting ~72 s and printing "fetch failed" (c1a8112).previewleaves the project's HTML files as they are; it no longer stampsdata-hf-idinto every file (26e8891).checkruns the browser audits past a lint error; it used to skip layout/motion/contrast whenever lint failed (a275f04).aaa290e).cloud rendertakes a composition at any aspect ratio (2:1 included) without the misleading 16:9 warning (18605b9).e4ac55c).media-use avatars: the HyperFrames account's own avatar looks, mirroringmedia-use voices, so templates stop listing avatars through the separateheygensign-in (a13908c).Draft while the full-suite fixes land.
Related work
Refs #6842. Companions: #7164 (style-sampling skill + packs), #7168 (render watchdog, lock, fonts), #7169 (audio attribute lint).
Test plan
🤖 Generated with Claude Code