Repository navigation
fix(cli): no auto-update across 0.x minors; install skills at the CLI's release tag - #7013
Conversation
…'s release tag - autoUpdate: before 1.0 a minor bump counts as a major one, so 0.8.x -> 0.9.x is a notice, not a silent background install. From 1.0 on, the major alone. - skills: `skills update` / bare `skills` / `init` install from heygen-com/hyperframes#v<VERSION>, and `skills check` plus the background freshness nudge read the manifest at the same tag. A build the repo has no tag for (dev build) falls back to main, as before. - skills: run the upstream installer as `npx skills@1.7.4` instead of an unpinned `npx skills`. 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. |
Comment ratchet: trim the comments added in the previous commit. No code change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ting it scripts/clawhub-unlist-retired.mjs loads skillsManifest.ts from source under plain node, which cannot resolve a relative `../version.js` import. Callers now pass `cliVersion` (and skillsSourceRef takes it as an argument), so the module keeps importing only node builtins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit accuracy: accurate 271 (base branch 271), smooth 103 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (2)
|
There was a problem hiding this comment.
Verdict: COMMENT (draft — no blockers) · 0 blocker · 2 important · 0 nits · head 7e1587f
The auto-update guard (breakingLine) looks right: 0.8→0.9 and 0.9→1.0 skip, patches still install, and unparsable versions keep the old allow behaviour. The two findings below are about the skills path.
Scope
Read the full diff. Checked that publish.yml pushes v<VERSION> before npm publish, so every published build has its tag, and that skills@1.5.13 and @1.7.4 both parse #ref. Actions at this head are green. There were no earlier reviews.
…5.13 - A release build reads the manifest at its own tag directly (publish pushes the tag before npm publish). Only a 404 for that manifest falls back to main; a timeout, missing git or proxy error now surfaces instead of quietly comparing against main, so the background nudge can't cache a false "outdated" count. - checkSkills returns the ref it read, and skills update installs from that same ref, so check and install can't disagree within one run. - Pin skills@1.5.13 (it parses `#<ref>` too) so the pin matches the version agentDirs.generated.ts and the lock-path notes were checked against. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fallow flagged fetchRemoteManifest's CRAP score (31.6 > 30). The tag fetch (404 is the only fallback to main) and the SHA-pinned main fetch are now their own functions. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
miguel-heygen
left a comment
There was a problem hiding this comment.
Independent review at 5f5752f0a814f5be002eac26b89c1d58436590ed, covering all 11 changed paths and their consumers. The 404-only tag fallback (skillsManifest.ts:663–675) and passing the checked ref into the pinned installer (skills.ts:410) resolve Genesis's earlier findings.
Blocker — the new breaking-line guard still permits a silent Homebrew minor jump. autoUpdate.ts:249–253 checks the registry target, but the supported Homebrew path at autoUpdate.ts:268–274 uses installerDetection.ts:182–185, which ignores that target and emits brew upgrade hyperframes. The detached child executes those arguments unchanged. With installed 0.8.231 and cached latest 0.8.232, the new guard passes; if the tap already contains 0.9.3, or advances while the child waits, the actual silent installation crosses the protected minor boundary. The completion marker also records the requested patch rather than the installed version.
The unversioned command predates this PR. This is an incomplete fix of the PR's new safety contract across a supported installer, not a newly introduced command. Skip Homebrew background installs until the eventual target can be enforced, retaining explicit manual upgrades. Add a scheduler-to-installer regression test using the real invocation helper; checking the formula before the detached wait alone leaves the race open.
Evidence: exact-source controlled probes confirm the allowed patch schedules unversioned Brew arguments and a simulated newer tap bypasses the boundary. No real Brew/install operation ran. Hosted logs witness all 90 cases in the four changed test files passing and a real tagged skills clone through skills@1.5.13; those runs used synthetic merge 7f254365, and do not test this target drift. No queue or merge action.
Verdict: REQUEST CHANGES
Reasoning: The registry predicate does not constrain the actual Homebrew install target, so the advertised silent-update boundary remains bypassable.
— Magi (Home)
`brew upgrade hyperframes` installs whatever formula the tap holds, so a background run scheduled for an allowed patch could still cross a 0.x minor. Homebrew installs now only get the update notice naming `brew upgrade`. A new test drives the scheduler through the real installer detection and installer script: no spawn on Homebrew, a versioned npm install for a patch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: APPROVE · 0 resolved, 0 open, 0 new · 5f5752f → 144e889. Covers this sha only. My approval at 5f5752f missed the Homebrew path; @miguel-heygen's blocker is fixed here. The background installer now skips brew, and hyperframes upgrade still runs brew. autoUpdate.invocation.test.ts fails against 5f5752f and passes 24/24 here, which I reproduced locally. Required CI is green; attempt 1 failures (coreRuntimeBrowser.test.ts and a cli 2/2 timeout) are outside the diff and passed on rerun.
miguel-heygen
left a comment
There was a problem hiding this comment.
Independent re-review at 144e889627b97ba521920e31287321e2026a5059, superseding my changes request at 5f5752f.
The Homebrew blocker is fixed: autoUpdate.ts:259–283 refuses Brew before writing pending state or launching a child. npm/bun/pnpm retain exact-version arguments; the unchanged notice and manual-upgrade paths retain brew upgrade hyperframes. The docs now describe this boundary accurately. The new real-helper invocation test checks both Brew refusal/notice and pinned npm installation.
Read all current peer bodies and audited the three-file delta plus the full 12-path PR, verifying unchanged consumer bytes against the prior audit. Genesis's current approval also acknowledges the previous gap. Fourteen independent exact-source scheduler/detection probes pass; no real child or package manager ran locally. Hosted logs show the two new invocation tests and 22 existing auto-update tests passing.
Initial CI was not all green: the producer browser test failed a retained-node assertion, and CLI 2/2 was cancelled. The original whole logs are preserved; the cancellation cause is not independently established. The producer rerun passes 267 cases and CLI 2/2 passes 3,354, with 89 skipped. Hosted execution used synthetic merge f4a2e97a into c14d92a2, rather than an isolated PR tree or the current main base. No live Homebrew/Windows updater acceptance is claimed.
Verdict: APPROVE
Reasoning: Homebrew can no longer bypass the silent-update boundary, and the allowed installers retain pinned targets. No remaining code blocker found. No queue, merge, or release action.
— Magi (Home)
Adopted with tests that fail on the old code (except the link change): - offload: rewrite media inside <template>, keep same-named files from other folders (heygen-com#6842, offload part only) - autoUpdate: no background upgrade across a 0.x minor; Homebrew installs only notify (heygen-com#7013, autoUpdate part only) - engine: script load failures carry origin/code; aborted scripts are not load failures (heygen-com#7088, heygen-com#7093) - community Discord invite links (heygen-com#7097) - studio: write media duration to the store once per file (heygen-com#6745) - check: restart the idle watchdog on each driver call during analysis (heygen-com#6919, adapted to this line's fixed 120s idle window) - check: default wait raised from 10s to 45s, matching snapshot/render (heygen-com#6947) - image cancellations no longer ignored by extension (heygen-com#6928) - capture: system sleep no longer counts as a stall (heygen-com#7096, hand-ported; the sequential branch also uses the shared stall clock) Commit watermark advances to 183614b (28 consecutive commits with file:line evidence); PR and issue watermarks are unchanged. The rest of the review is in docs/UPSTREAM_REVIEW_2026-11-04_CONTINUED.md. Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com> Co-authored-by: WaterrrForever <miao.yang@heygen.com> Co-authored-by: Wenbo Zhu <wenbo_zhu@berkeley.edu> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
Three fixes to how the CLI updates itself and its skills.
major.minor(0.8 vs 0.9 is a major jump: notice only, no install); from 1.0 on it compares the major. Patch updates inside one minor (0.9.2 → 0.9.3) still auto-install.main.skills update, bareskillsandinitnow install fromhttps://github.com/heygen-com/hyperframes#v<VERSION>.skills checkand the background freshness nudge readskills-manifest.jsonat the same tag. There is no up-frontgit ls-remoteprobe:publish.ymlpushesv<VERSION>beforenpm publish, so a release build reads its tag directly. Only a 404 for the tag's manifest falls back tomain; a timeout, missing git or proxy error surfaces as an error (skills updatethen takes its existing offline path and keeps what is installed; the background nudge writes nothing). The ref is decided once per run:checkSkillsreturns the ref it read, andskills updateinstalls from that same ref. Dev / pre-release builds usemain, as today. Release tags are the npm-published commits (checked:npm view hyperframes@0.9.3 gitHead=v0.9.3=f6536e9; same for 0.9.2, 0.8.231).skillsCLI is pinned.npx skills add …→npx skills@1.5.13 add …, the versionagentDirs.generated.ts(scripts/sync-agent-dirs.tsSKILLS_REF) and the lock-path notes were checked against, so the pin and the mirror table agree. 1.5.13 parses the#<ref>fragment (parseFragmentRef) and clones with--branch <ref>(cloneRepo); checked in its publisheddist/cli.mjs, and a realnpx skills@1.5.13 add https://github.com/heygen-com/hyperframes#v0.9.2 … --full-depthin a sandbox printedSource: …hyperframes.git @ v0.9.2, wrote lockref: v0.9.2, and installedhyperframes-clibyte-identical tov0.9.2(13/13 files; 12/13 matchmain).No skill text changes. Docs:
docs/packages/cli.mdx,README.md,CLAUDE.mdsaidskills updateinstalls frommain; they now say it installs at the tag matching the CLI.Why
mainholds today while driving an older CLI from npm; the skills can reference flags the installed CLI does not have. For a 0.9.2 CLI today, 4 skills onmaindiffer fromv0.9.2(hyperframes,hyperframes-cli,media-use,reverse-any-video).npx skillsruns whatever upstream published last, so an upstream release could change every install with no HyperFrames release.How
autoUpdate.ts:majorOf→breakingLine(0.<minor>before 1.0,<major>after). Unparsable versions keep the old "allow" behaviour.skillsManifest.ts: newcliReleaseTag().checkSkillstakes acliVersionoption and reads the raw manifest at that tag (tags do not move, so no SHA pinning needed);fetchManifestthrows a typedManifestHttpError, and only its 404 falls back to the unchangedmainpath.SkillsCheckResultgainsref(the ref the manifest was read at; null for a local file or URL). Callers (skills update/skills check/ the background nudge) passVERSION;skillsManifest.tsitself still imports only node builtins, becausescripts/clawhub-unlist-retired.mjsloads it from source under plain node.commands/skills.ts:installSkillstakes the ref from the caller and appends#<ref>to the clone URL:updateSkillspassescheck.ref; the offline path (manifest unreachable) passescliReleaseTag(VERSION) ?? "main".SKILLS_CLI = "skills@1.5.13".Test plan
vitest runon the touched files: 148 passed;node --test scripts/clawhub-unlist-retired.test.mjs7 passed;tsc --noEmitclean; oxlint/oxfmt clean)Fails without the fix (the PR's tests run against the
mainsource files: 15 failed):autoUpdate.test.ts > does NOT schedule across a 0.x minor jump(main schedules the 0.8.231 → 0.9.3 install)skillsManifest.releaseTag.test.ts > reads the manifest at the CLI's release tag without asking git first(main fetches themainmanifest) andskills.test.ts > skills update installs at the ref its check read, through the pinned skills CLI. The review follow-updoes not report skills outdated against main when the git lookup failsfails at 7e1587f withexpected 1 to be +0(a failedls-remotecompared a v0.9.2 install againstmain).skills.test.ts > uses linux-compatible npx command for preflight and the full install(main spawnsskills, notskills@1.5.13)E2E (pod sandbox: own HOME / npm prefix / npm cache / XDG dirs,
env -i, telemetry off; real TTY viascript; CLI built frommainf6536e9 and from this branch at 7e1587f, which still pinnedskills@1.7.4and probed the tag withls-remote; the 1.5.13 pin was re-checked at 275ba72 with the real install above):hyperframes infonpm install -g hyperframes@0.9.3; next run printedhyperframes auto-updated to v0.9.3,--version= 0.9.3auto-update.log:[skip] major-bump 0.8.231 -> 0.9.3; no install after 120 s; terminal showsUpdate available: 0.8.231 → 0.9.3/Run: npm install -g hyperframes@0.9.3; still 0.8.231auto-updated to v0.9.3)skills updatethenskills checkmain: 3 of 4 core skills differ fromv0.9.2(hyperframes,hyperframes-cli,media-use); lockref: nullSource: …hyperframes.git @ v0.9.2; lockref: v0.9.2; 4 current / 0 outdated; all 220 installed files byte-matchv0.9.2skills check: 1 current, 3 outdated (exit 1);skills updatereinstalls those 3 at#v0.9.2; re-check 4 currentmain(no#ref), 0 outdated, files == mainnpx skills add https://github.com/heygen-com/hyperframes …npx skills@1.7.4 add https://github.com/heygen-com/hyperframes#v0.9.2 …Sandbox:
env -i, own HOME / npm prefix / cache / XDG,HYPERFRAMES_NO_TELEMETRY=1 DO_NOT_TRACK=1 DISABLE_TELEMETRY=1; the built dist is swapped into the published 0.9.3 package and its bakedVERSIONrelabelled (0.8.231 / 0.9.2 / 0.9.99). 0.9.2 is used for J2 becausemainwas still equal tov0.9.3at the time.Draft — please don't add to the merge queue; owner (Wenbo) will review first.
— wanbi
🤖 Generated with Claude Code