Skill Tracer
Skills › HyperFrames › hyperframes-cli › upgrade-info-misc.md

upgrade-info-misc.md

134 lines · skills/hyperframes-cli/references/upgrade-info-misc.md at a595755

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# info, upgrade, compositions, timeline, docs, benchmark, telemetry, asset preprocessing
2
3Catch-all reference for commands that don't fit the main dev loop.
4

info, upgrade, compositions, timeline, docs, benchmark, telemetry, asset preprocessing

Catch-all reference for commands that don't fit the main dev loop.

Raw lines 1 to 4
5## info
6
7```bash
8npx hyperframes info # project metadata
9npx hyperframes info ./my-video # specific project
10npx hyperframes info --json
11```
13Prints **project** metadata: name, resolution, duration, element counts by type, track count, and total project size. Project-level — not environment. For environment health use `doctor`.

info

npx hyperframes info                   # project metadata
npx hyperframes info ./my-video        # specific project
npx hyperframes info --json

Prints project metadata: name, resolution, duration, element counts by type, track count, and total project size. Project-level — not environment. For environment health use doctor.

Raw lines 5 to 14
15## upgrade
17```bash
18npx hyperframes upgrade # check + interactive prompt
19npx hyperframes upgrade --check # check and exit, no prompt (agent-friendly)
20npx hyperframes upgrade --check --json # machine-readable: current / latest / updateAvailable
21npx hyperframes upgrade --yes # print upgrade commands without prompting
22```
24Compares the installed CLI version against npm latest.
26`--project [dir]` bumps a **project's** pinned scripts instead of the global install: it rewrites every `npx …hyperframes@<version>…` in `<dir>/package.json` (default cwd) to npm-latest. Always invoke it unpinned (`npx hyperframes@latest upgrade --project`) — a project scaffolded on an old CLI stays frozen otherwise. `--project . --check` reports the delta without writing; add `--json` for `{ changed, from, to, path }`. Pass the dir explicitly whenever another flag follows `--project` — on older releases a bare `--project` consumes the next flag as its directory value.

upgrade

npx hyperframes upgrade                # check + interactive prompt
npx hyperframes upgrade --check        # check and exit, no prompt (agent-friendly)
npx hyperframes upgrade --check --json # machine-readable: current / latest / updateAvailable
npx hyperframes upgrade --yes          # print upgrade commands without prompting

Compares the installed CLI version against npm latest.

--project [dir] bumps a project's pinned scripts instead of the global install: it rewrites every npx …hyperframes@<version>… in <dir>/package.json (default cwd) to npm-latest. Always invoke it unpinned (npx hyperframes@latest upgrade --project) — a project scaffolded on an old CLI stays frozen otherwise. --project . --check reports the delta without writing; add --json for { changed, from, to, path }. Pass the dir explicitly whenever another flag follows --project — on older releases a bare --project consumes the next flag as its directory value.

Raw lines 15 to 27
28## timeline
30```bash
31npx hyperframes timeline [project-dir] # tracks and clips as a table with bars
32npx hyperframes timeline [project-dir] --json
33```
35Reach for `timeline` instead of opening `index.html` and each `data-composition-src` file when you need to know what is on the timeline: which clips exist, when they start and end, what they play, and how loud. It reads the project's files statically (no browser).
37Text output is `timeline <N>s`, then one block per track kind (`video`, `graphics`, `captions`, `audio`) with one row per clip of that kind, ordered by absolute start:
39```
40graphics (2: 1 top-level, 1 nested)
41 |██████ | sec-connector 0-6.7s src=compositions/connector-morph.html
42 |██████████████ | box 15.67-17.99s (local 0-2.32s) nested in sec-connector compositions/connector-morph.html
43audio (1)
44 | █ | vo 1.6-3.6s src=vo.mp3 vol=0.5 group=vo volume[0:0.2 2:1]
45```
47- The bar is 40 columns over the whole timeline. Times are seconds.
48- `src=`, `vol=`, `rate=` (playback rate, only when not 1), `group=` (audio group), and `<target>[t:v ...]` (automation lane points, `t` in seconds from the clip start) appear only when the clip has them.
49- The header counts every clip of that kind, nested ones included: `video (6: 2 top-level, 4 nested)`. The list is in absolute order, so the Nth row is the Nth clip of that kind on the main timeline. A clip inside a sub-composition prints its absolute start-end, then `(local <start>-<end>s)` (time inside that sub-composition), then `nested in <host row id> <file that declares it>`. Only one level of nesting is read: a sub-composition inside a sub-composition is listed as a row saying `children=unread`, and the clips inside it are not counted.
50- With no `data-duration`/`data-end`, a media row still gets a resolved length and says where it came from: `duration=media` means ffprobe measured the source (with playback start and rate applied); `duration=default` means an `img` got the 3s default; `duration=inferred` means a composition host summed its children; `pending: <reason>` (dotted bar, `duration` 0) means the source could not be probed (missing file, remote `src`, ffprobe error). A non-media leaf with nothing to resolve prints no source.
51- `lanes unreadable: ...` means the clip's `data-automation` or `data-fx-chain` did not parse; fix the attribute.
53`--json` prints `{ timeline: { duration, tracks: [{ kind, rows: [...] }] } }`. A track's `rows` are every clip of that kind, nested ones included, by `absStart`; read them, never only the top level. Each row has `id`, `kind` (tag), `trackKind`, `start`, `duration`, `end` (local to the row's own file), **`absStart`, `absEnd`, `file`** (main-timeline time and the project-relative file that declares the clip — use these, not `start`/`end`, to compare clips across nesting), `trackIndex`, `src`, `sourceFile`, `volume`, `lanes`, `playbackRate`, `audioGroup`, `durationAuthored`, **`durationSource`** (`"authored" | "media" | "default" | "inner" | "pending"`, or `null` for a non-media leaf with nothing to resolve), **`pendingReason`** (why nothing resolved; `null` unless `durationSource` is `"pending"`), `laneError`, **`index`** (the row's position in its kind's `rows`; a position, not an id), **`nested`** (declared inside a sub-composition), **`host`** (plain id of the row that hosts a nested clip, else `null`), **`hostRow`** (`{kind, index}` of that host row), and `children` (`{kind, index}` pointers to the sub-composition's clips, one level; every clip is already a full row in its kind's `rows`, so nothing needs following).

timeline

npx hyperframes timeline [project-dir]          # tracks and clips as a table with bars
npx hyperframes timeline [project-dir] --json

Reach for timeline instead of opening index.html and each data-composition-src file when you need to know what is on the timeline: which clips exist, when they start and end, what they play, and how loud. It reads the project's files statically (no browser).

Text output is timeline <N>s, then one block per track kind (video, graphics, captions, audio) with one row per clip of that kind, ordered by absolute start:

graphics (2: 1 top-level, 1 nested)
  |██████                                  | sec-connector 0-6.7s src=compositions/connector-morph.html
  |██████████████                          | box 15.67-17.99s (local 0-2.32s) nested in sec-connector compositions/connector-morph.html
audio (1)
  | █                                      | vo 1.6-3.6s src=vo.mp3 vol=0.5 group=vo volume[0:0.2 2:1]
  • The bar is 40 columns over the whole timeline. Times are seconds.
  • src=, vol=, rate= (playback rate, only when not 1), group= (audio group), and <target>[t:v ...] (automation lane points, t in seconds from the clip start) appear only when the clip has them.
  • The header counts every clip of that kind, nested ones included: video (6: 2 top-level, 4 nested). The list is in absolute order, so the Nth row is the Nth clip of that kind on the main timeline. A clip inside a sub-composition prints its absolute start-end, then (local <start>-<end>s) (time inside that sub-composition), then nested in <host row id> <file that declares it>. Only one level of nesting is read: a sub-composition inside a sub-composition is listed as a row saying children=unread, and the clips inside it are not counted.
  • With no data-duration/data-end, a media row still gets a resolved length and says where it came from: duration=media means ffprobe measured the source (with playback start and rate applied); duration=default means an img got the 3s default; duration=inferred means a composition host summed its children; pending: <reason> (dotted bar, duration 0) means the source could not be probed (missing file, remote src, ffprobe error). A non-media leaf with nothing to resolve prints no source.
  • lanes unreadable: ... means the clip's data-automation or data-fx-chain did not parse; fix the attribute.

--json prints { timeline: { duration, tracks: [{ kind, rows: [...] }] } }. A track's rows are every clip of that kind, nested ones included, by absStart; read them, never only the top level. Each row has id, kind (tag), trackKind, start, duration, end (local to the row's own file), **absStart, absEnd, file** (main-timeline time and the project-relative file that declares the clip — use these, not start/end, to compare clips across nesting), trackIndex, src, sourceFile, volume, lanes, playbackRate, audioGroup, durationAuthored, **durationSource** ("authored" | "media" | "default" | "inner" | "pending", or null for a non-media leaf with nothing to resolve), **pendingReason** (why nothing resolved; null unless durationSource is "pending"), laneError, **index** (the row's position in its kind's rows; a position, not an id), **nested (declared inside a sub-composition), host** (plain id of the row that hosts a nested clip, else null), **hostRow** ({kind, index} of that host row), and children ({kind, index} pointers to the sub-composition's clips, one level; every clip is already a full row in its kind's rows, so nothing needs following).

Raw lines 28 to 54
55### Query one-liners (jq, node fallback if jq is absent)
57```bash
58TL=$(npx hyperframes timeline --json)
59# 1. what plays at absolute time T=12.5
60jq --argjson t 12.5 '[.timeline.tracks[].rows[] | select(.absStart<=$t and .absEnd>$t)]' <<<"$TL"
61node -e 'const t=12.5,j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.forEach(tr=>tr.rows.forEach(x=>{if(x.absStart<=t&&x.absEnd>t)console.log(x.id,x.file)}))' <<<"$TL"
62# 2. find a clip by id or src -> file, track, absStart, absEnd
63jq --arg q tsfx-pet2 '[.timeline.tracks[].rows[] | select(.id==$q or .src==$q)] | .[] | {file,trackKind,absStart,absEnd}' <<<"$TL"
64node -e 'const q="tsfx-pet2",j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.forEach(tr=>tr.rows.forEach(x=>{if(x.id===q||x.src===q)console.log(x.file,x.trackKind,x.absStart,x.absEnd)}))' <<<"$TL"
65# 3. every clip of one kind, nested included, in absolute order
66jq --arg k video '.timeline.tracks[] | select(.kind==$k).rows[] | {id,absStart,absEnd}' <<<"$TL"
67node -e 'const k="video",j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.find(t=>t.kind===k).rows.forEach(r=>console.log(r.id,r.absStart,r.absEnd))' <<<"$TL"
68# 4. gaps and overlaps within a kind (positive = gap, negative = overlap)
69jq --arg k video '(.timeline.tracks[] | select(.kind==$k).rows) as $r|[range(0;($r|length)-1)|{a:$r[.].id,b:$r[.+1].id,delta:($r[.+1].absStart-$r[.].absEnd)}]' <<<"$TL"
70node -e 'const k="video",j=JSON.parse(require("fs").readFileSync(0,"utf8"));const r=j.timeline.tracks.find(t=>t.kind===k).rows;for(let i=0;i<r.length-1;i++)console.log(r[i].id,r[i+1].id,r[i+1].absStart-r[i].absEnd)' <<<"$TL"
71# 5. the Nth clip of a kind by absolute start (N=2)
72jq --arg k video --argjson n 2 '.timeline.tracks[] | select(.kind==$k).rows[$n-1] | {index,id,absStart,file,nested}' <<<"$TL"
73node -e 'const k="video",n=2,j=JSON.parse(require("fs").readFileSync(0,"utf8"));const r=j.timeline.tracks.find(t=>t.kind===k).rows[n-1];console.log(r.index,r.id,r.absStart,r.file)' <<<"$TL"
74```

Query one-liners (jq, node fallback if jq is absent)

TL=$(npx hyperframes timeline --json)
# 1. what plays at absolute time T=12.5
jq --argjson t 12.5 '[.timeline.tracks[].rows[] | select(.absStart<=$t and .absEnd>$t)]' <<<"$TL"
node -e 'const t=12.5,j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.forEach(tr=>tr.rows.forEach(x=>{if(x.absStart<=t&&x.absEnd>t)console.log(x.id,x.file)}))' <<<"$TL"
# 2. find a clip by id or src -> file, track, absStart, absEnd
jq --arg q tsfx-pet2 '[.timeline.tracks[].rows[] | select(.id==$q or .src==$q)] | .[] | {file,trackKind,absStart,absEnd}' <<<"$TL"
node -e 'const q="tsfx-pet2",j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.forEach(tr=>tr.rows.forEach(x=>{if(x.id===q||x.src===q)console.log(x.file,x.trackKind,x.absStart,x.absEnd)}))' <<<"$TL"
# 3. every clip of one kind, nested included, in absolute order
jq --arg k video '.timeline.tracks[] | select(.kind==$k).rows[] | {id,absStart,absEnd}' <<<"$TL"
node -e 'const k="video",j=JSON.parse(require("fs").readFileSync(0,"utf8"));j.timeline.tracks.find(t=>t.kind===k).rows.forEach(r=>console.log(r.id,r.absStart,r.absEnd))' <<<"$TL"
# 4. gaps and overlaps within a kind (positive = gap, negative = overlap)
jq --arg k video '(.timeline.tracks[] | select(.kind==$k).rows) as $r|[range(0;($r|length)-1)|{a:$r[.].id,b:$r[.+1].id,delta:($r[.+1].absStart-$r[.].absEnd)}]' <<<"$TL"
node -e 'const k="video",j=JSON.parse(require("fs").readFileSync(0,"utf8"));const r=j.timeline.tracks.find(t=>t.kind===k).rows;for(let i=0;i<r.length-1;i++)console.log(r[i].id,r[i+1].id,r[i+1].absStart-r[i].absEnd)' <<<"$TL"
# 5. the Nth clip of a kind by absolute start (N=2)
jq --arg k video --argjson n 2 '.timeline.tracks[] | select(.kind==$k).rows[$n-1] | {index,id,absStart,file,nested}' <<<"$TL"
node -e 'const k="video",n=2,j=JSON.parse(require("fs").readFileSync(0,"utf8"));const r=j.timeline.tracks.find(t=>t.kind===k).rows[n-1];console.log(r.index,r.id,r.absStart,r.file)' <<<"$TL"
Raw lines 55 to 75
76## compositions, docs
78```bash
79npx hyperframes compositions # list compositions in project
80npx hyperframes compositions --json
81npx hyperframes docs # list available topics
82npx hyperframes docs rendering # print one topic inline in the terminal
83```
85`compositions` lists every `data-composition-id` in the project (including sub-comps) with duration, resolution, and element count.
87`docs` prints inline documentation **in the terminal** — it does not open a browser. Topics: `data-attributes`, `examples`, `rendering`, `gsap`, `troubleshooting`, `compositions`. Run without a topic to see the list.

compositions, docs

npx hyperframes compositions           # list compositions in project
npx hyperframes compositions --json
npx hyperframes docs                   # list available topics
npx hyperframes docs rendering         # print one topic inline in the terminal

compositions lists every data-composition-id in the project (including sub-comps) with duration, resolution, and element count.

docs prints inline documentation in the terminal — it does not open a browser. Topics: data-attributes, examples, rendering, gsap, troubleshooting, compositions. Run without a topic to see the list.

Raw lines 76 to 88
89## benchmark
91```bash
92npx hyperframes benchmark # run the preset matrix in current project
93npx hyperframes benchmark ./my-video # specific project
94npx hyperframes benchmark --runs 5 # repeat each config N times (default 3)
95npx hyperframes benchmark --json
96```
98Renders the project with 5 preset configurations — `30fps draft 2w`, `30fps standard 2w`, `30fps high 2w`, `30fps standard 4w`, `60fps standard 4w` — and prints a comparison of render speed and output file size. Use it to find the fastest acceptable preset for your machine. Not a single-render-with-stage-breakdown.

benchmark

npx hyperframes benchmark              # run the preset matrix in current project
npx hyperframes benchmark ./my-video   # specific project
npx hyperframes benchmark --runs 5     # repeat each config N times (default 3)
npx hyperframes benchmark --json

Renders the project with 5 preset configurations — 30fps draft 2w, 30fps standard 2w, 30fps high 2w, 30fps standard 4w, 60fps standard 4w — and prints a comparison of render speed and output file size. Use it to find the fastest acceptable preset for your machine. Not a single-render-with-stage-breakdown.

Raw lines 89 to 99
100## telemetry
102```bash
103npx hyperframes telemetry status # show telemetry state
104npx hyperframes telemetry disable # disable usage telemetry
105npx hyperframes telemetry enable # re-enable telemetry
106```
108Telemetry is usage counters only. It is anonymous until the user signs in to HeyGen; after `auth login` it is linked to their HeyGen account (email and username), so don't tell a signed-in user it is anonymous. Disable globally with `HYPERFRAMES_NO_TELEMETRY=1` if env-var control is preferred over the subcommand.
110Events include two fingerprint properties used to distinguish managed-sandbox runs from real laptops — no PII, no env-var **values**, only existence checks:
112- **`sandbox_runtime`**: `gvisor` / `firecracker` / `docker` / `kvm` / `wsl` / `null`. gVisor via kernel string + `/proc/version`. Firecracker via `/dev/vsock` + DMI sys_vendor. Docker via `/.dockerenv` + cgroup.
113- **`agent_runtime`**: `claude_code` / `codex` / `cursor` / `copilot_agent` / `jules` / `replit` / `devin` / `aider` / `gemini_cli` / `hermes` / `openclaw` / `null`. Detected by the existence of well-known vendor env vars; the values themselves are never read.
114- **`client`**: set only when an app launched the CLI with a `HYPERFRAMES_CLIENT` tag (`<app>/<version>/<channel>`), sent as-is when it is a short slug.

telemetry

npx hyperframes telemetry status      # show telemetry state
npx hyperframes telemetry disable     # disable usage telemetry
npx hyperframes telemetry enable      # re-enable telemetry

Telemetry is usage counters only. It is anonymous until the user signs in to HeyGen; after auth login it is linked to their HeyGen account (email and username), so don't tell a signed-in user it is anonymous. Disable globally with HYPERFRAMES_NO_TELEMETRY=1 if env-var control is preferred over the subcommand.

Events include two fingerprint properties used to distinguish managed-sandbox runs from real laptops — no PII, no env-var values, only existence checks:

  • **sandbox_runtime**: gvisor / firecracker / docker / kvm / wsl / null. gVisor via kernel string + /proc/version. Firecracker via /dev/vsock + DMI sys_vendor. Docker via /.dockerenv + cgroup.
  • **agent_runtime**: claude_code / codex / cursor / copilot_agent / jules / replit / devin / aider / gemini_cli / hermes / openclaw / null. Detected by the existence of well-known vendor env vars; the values themselves are never read.
  • **client**: set only when an app launched the CLI with a HYPERFRAMES_CLIENT tag (<app>/<version>/<channel>), sent as-is when it is a short slug.
Raw lines 100 to 115
116## Asset Preprocessing
118```bash
119npx hyperframes tts
120npx hyperframes transcribe
121npx hyperframes remove-background
122```
124These produce assets (narration audio, word-level transcripts, transparent video) that get dropped into a composition. Each may download its own model on first run.
126For voice selection, Whisper model rules, output format choice, and the TTS → transcript → captions chain, invoke the `media-use` skill. This skill stays focused on the dev loop.

Asset Preprocessing

npx hyperframes tts
npx hyperframes transcribe
npx hyperframes remove-background

These produce assets (narration audio, word-level transcripts, transparent video) that get dropped into a composition. Each may download its own model on first run.

For voice selection, Whisper model rules, output format choice, and the TTS → transcript → captions chain, invoke the media-use skill. This skill stays focused on the dev loop.

Raw lines 116 to 127
Names a skill media-use :126
128## Remaining harness usage
130Run `npx hyperframes usage --json` at the start of a video workflow and again at milestones such as after drafting and before rendering. A fresh read at handoff can serve as the start read. Use `--harness claude-code`, `--harness codex`, or `--harness grok` to select explicitly.
132Known results contain `status: "known"`, `harness`, `planTier`, `session`, `weekly`, and `spend`. Each available window contains `usedPercent`, `remainingPercent`, and `resetsAt`; an unavailable window is `null`. `planTier` is the readable subscription tier when available, otherwise `null`. Claude Code reports its shared five-hour and weekly windows; a spend-metered plan (such as Enterprise) has neither and reports `spend`, the share of its billing-period spend limit already used, with `resetsAt: null`. Codex reports its shared session and weekly windows when available. Grok reports its included weekly allowance with `session: null`. Only Claude Code reports `spend`; it is `null` elsewhere. When no window is available the result is `status: "unknown"` with `reason: "no_usage_windows"`.
134Unknown results contain `status: "unknown"` and a token-free `reason`. Missing, expired, unsupported, ambiguous, or unreadable logins and unavailable provider responses return unknown. Report the unknown state without guessing allowance. The command reads existing credentials without refreshing or rewriting them and emits no tokens or telemetry. Usage is a snapshot; it does not reserve allowance or estimate the next video's cost. Keep scope and workflow choices with the user.

Remaining harness usage

Run npx hyperframes usage --json at the start of a video workflow and again at milestones such as after drafting and before rendering. A fresh read at handoff can serve as the start read. Use --harness claude-code, --harness codex, or --harness grok to select explicitly.

Known results contain status: "known", harness, planTier, session, weekly, and spend. Each available window contains usedPercent, remainingPercent, and resetsAt; an unavailable window is null. planTier is the readable subscription tier when available, otherwise null. Claude Code reports its shared five-hour and weekly windows; a spend-metered plan (such as Enterprise) has neither and reports spend, the share of its billing-period spend limit already used, with resetsAt: null. Codex reports its shared session and weekly windows when available. Grok reports its included weekly allowance with session: null. Only Claude Code reports spend; it is null elsewhere. When no window is available the result is status: "unknown" with reason: "no_usage_windows".

Unknown results contain status: "unknown" and a token-free reason. Missing, expired, unsupported, ambiguous, or unreadable logins and unavailable provider responses return unknown. Report the unknown state without guessing allowance. The command reads existing credentials without refreshing or rewriting them and emits no tokens or telemetry. Usage is a snapshot; it does not reserve allowance or estimate the next video's cost. Keep scope and workflow choices with the user.

Raw lines 128 to 134