diff --git a/docs/packages/cli.mdx b/docs/packages/cli.mdx index 092ea058ce5..1c722fea9dc 100644 --- a/docs/packages/cli.mdx +++ b/docs/packages/cli.mdx @@ -130,6 +130,22 @@ There, a command that would ask for confirmation, such as `publish` or `upgrade` exits 2 instead and names the flag to pass (`--yes`), and spinners print only their final line, on stderr. +**`npx` installs before the CLI runs.** The guarantee above starts once the CLI +is running, and `npx` keeps it: with no terminal, npm skips its +`Ok to proceed?` prompt, prints a warning, and installs. What `npx` adds is the +install itself. An unversioned `npx hyperframes` asks the registry for the +latest release on every run and installs it when it is new there, so two jobs +that start together can collide in npm's cache (`_cacache` for the fetch, +`_npx` for the install: `EEXIST` or `ENOTEMPTY`; a retry succeeds), and a new +release silently changes +what the same command renders. In scripts and CI, run the `npm run` scripts a +scaffolded project ships (`npm run render` is `npx --yes hyperframes@X.Y.Z`, +pinned to the version that created the project), or pin the same way yourself. +An installed binary (`npm i hyperframes@X.Y.Z`, then +`node_modules/.bin/hyperframes`, or a global install) skips the fetch +entirely. Check the render's dimensions and duration with `ffprobe` before +anything downstream consumes it. + **Exit codes.** `0` means the command succeeded, `1` means it ran and failed, and `2` means the command line itself is wrong: an unknown command or flag, or a missing or invalid value. diff --git a/scripts/check-core-skills.mjs b/scripts/check-core-skills.mjs index 50127b192a2..df383db9e36 100644 --- a/scripts/check-core-skills.mjs +++ b/scripts/check-core-skills.mjs @@ -16,7 +16,8 @@ export const CORE_SKILLS = { // +128 B for the routing rows to the video rebuilds and to a reference's style, which only trigger when the entry hands them on. hyperframes: 7488, // +256 B for the `_meta.updateNotice` line: the agent relays it, the person updates. - "hyperframes-cli": 7616, + // +256 B for the unattended pointer: a job with no TTY runs the wrapper or a pinned `npx --yes`. + "hyperframes-cli": 7872, "hyperframes-registry": 5312, "media-use": 5312, figma: 7360, diff --git a/skills-manifest.json b/skills-manifest.json index 3f80fefe2c1..0e9dd824b5a 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -10,8 +10,8 @@ "files": 80 }, "hyperframes-cli": { - "hash": "d6972257fbc99fc0", - "files": 13 + "hash": "3ff23dfb667d552f", + "files": 14 }, "hyperframes-registry": { "hash": "a032ccc5c7948ac2", diff --git a/skills/hyperframes-cli/SKILL.md b/skills/hyperframes-cli/SKILL.md index d7ce8f536e4..1b5d886a406 100644 --- a/skills/hyperframes-cli/SKILL.md +++ b/skills/hyperframes-cli/SKILL.md @@ -9,7 +9,7 @@ description: HyperFrames CLI - scaffold, check frames, edit timelines, preview, # HyperFrames CLI -Run `npx hyperframes ` unless the project gives a wrapper; then use the wrapper. It needs Node.js 22+ and FFmpeg. Every command has `--help`; most take `--json`, and a failure prints `✗ …`, a `Fix:` line and exits non-zero. +Run `npx hyperframes ` unless the project gives a wrapper (`npm run render` and friends); then use the wrapper. A job with no TTY runs the wrapper or `npx --yes hyperframes@X.Y.Z`, never bare `npx hyperframes` (`references/unattended.md`). It needs Node.js 22+ and FFmpeg. Every command has `--help`; most take `--json`, and a failure prints `✗ …`, a `Fix:` line and exits non-zero. A `--json` result may carry `_meta.updateNotice`: a newer HyperFrames release is out. Pass it to the person once per conversation, in your own words, at a natural pause; updating is theirs to decide. @@ -38,7 +38,7 @@ A `--json` result may carry `_meta.updateNotice`: a newer HyperFrames release is 2. `npx hyperframes check --json` and fix every error. While a lint error remains the layout and contrast audits don't run; "0 samples" means nothing was checked. Contrast failures carry a `suggestedColor`. A finding at a single sample (an entrance in flight) is info; a 3 s+ video with no visible change fails `sweep_static`. 3. `npx hyperframes snapshot` and read the PNGs (under `.hyperframes/artifacts/snapshots/`): that is how you see the video. With sub-compositions, snapshot a midpoint of every scene; tiny unstyled content or a missing hero is a mount defect (`../hyperframes/references/format.md`). 4. `npx hyperframes preview --background`, check the URL answers 200, give the person the project URL and wait, unless they asked for the file or for no stops. Passing checks alone is not a reason to render. -5. Time to render (step 4): `npx hyperframes render --quality looks -o out.mp4` (`draft` while iterating, `delivery` for the final; paid plan: `cloud render --fps --quality high -o out.mp4`). Confirm the file is non-empty and its `ffprobe` duration matches the root `data-duration`, then look at decoded frames. +5. Time to render (step 4): `npx hyperframes render --quality looks -o out.mp4` (`draft` while iterating, `delivery` for the final; paid plan: `cloud render --fps --quality high -o out.mp4`). Confirm the file is non-empty and `ffprobe` reports the root `data-duration` and the project's `data-width`/`data-height`, then look at decoded frames. "This element" or the current selection: `npx hyperframes preview --context --json --context-fields selection`; `no-selection` means ask them to click it. diff --git a/skills/hyperframes-cli/references/unattended.md b/skills/hyperframes-cli/references/unattended.md new file mode 100644 index 00000000000..cd9376a3db1 --- /dev/null +++ b/skills/hyperframes-cli/references/unattended.md @@ -0,0 +1,21 @@ +# Unattended runs + +Scripts, CI and scheduled jobs call the CLI with no TTY. Nothing prompts there: the CLI exits 2 and names the flag (`--yes`) instead of asking, and `npx` skips its own `Ok to proceed?` prompt whenever stdin is not a terminal or CI is detected — it prints a warning and installs. What can still fail is the install itself. + +## Bare `npx hyperframes` installs on every cold cache + +With no version, `npx` asks the registry for the latest release on every run and installs it under `~/.npm/_npx//` when it is not there yet. Two consequences for a job nobody is watching: + +- Two runs that start together race in npm's cache (`_cacache` for the fetch, `_npx` for the install). One can fail with `EEXIST` or `ENOTEMPTY` while the other is still writing; a retry succeeds, because by then the install is in place. +- A new release changes what the same command renders, silently. + +## Use the project's scripts, or pin + +- A scaffolded project (`hyperframes init`) already ships `npm run dev|check|render|publish`; each is `npx --yes hyperframes@X.Y.Z`, pinned to the version that created the project. Jobs run those. +- Outside a project, pin the same way: `npx --yes hyperframes@X.Y.Z`. To skip the fetch and the cache race altogether, install once — `npm i hyperframes@X.Y.Z` then `node_modules/.bin/hyperframes `, or `npm i -g hyperframes@X.Y.Z` then `hyperframes `. + +Interactive sessions float on purpose: `update` moves an `npx` user to `npx hyperframes@latest`, and the reverse-any-video skill runs `npx -y hyperframes@latest` when the installed CLI is behind. That is a person's call at a terminal. An unattended job pins. + +## Verify the output before anything consumes it + +Nobody watches an unattended render, so check it the way the loop's step 5 does before it ships downstream: `ffprobe` the file and confirm the dimensions match the project's `data-width`/`data-height` and the duration matches the root `data-duration`.