Skip to content

fix(cli): restore hyperframes capture <url>; move video download to --video flag#1475

Merged
ukimsanov merged 1 commit into
mainfrom
fix/capture-video-flag
Jun 15, 2026
Merged

fix(cli): restore hyperframes capture <url>; move video download to --video flag#1475
ukimsanov merged 1 commit into
mainfrom
fix/capture-video-flag

Conversation

@ukimsanov

Copy link
Copy Markdown
Collaborator

What

Restore hyperframes capture <url> (broken in v0.6.99) by replacing the capture video subcommand from #1447 with a --video <project> mode flag on the parent capture command.

Why

PR #1447 made video-download a citty subcommand of capture. citty's runCommand (dist/index.mjs:209-227) treats any non-flag positional as a subcommand-name attempt and throws E_UNKNOWN_COMMAND when it doesn't match — there's no fallback to the parent's positional args. So hyperframes capture https://vercel.com died with Unknown command https://vercel.com. Verified against a minimal repro of citty 0.2.2.

Per James's suggestion on #1447, expose video-download as a mode flag instead. Citty has no issue with a positional URL coexisting with flags, so both surfaces work side-by-side.

How

  • Drop subCommands + the parent-run guard from packages/cli/src/commands/capture.ts; make the url positional required: false.
  • Add --video, --index, --list, --video-url flags to capture. (--video-url instead of --url because the parent already has a url positional and citty rejects name collisions.)
  • Refactor packages/cli/src/commands/capture/video.ts to export runVideoMode(args) instead of a defineCommand default. All pure helpers (safeFilename, streamToFile, pickManifestEntry, findFilenameCollision, content-type whitelist, 250MB cap) are byte-identical.
  • Capture's run() dispatches on args.video: if set, call runVideoMode and return; otherwise treat args.url as the website URL.

Test plan

  • Unit tests: existing 22 tests in video.test.ts continue to pass (they cover pure helpers, not the citty wrapper); 843 CLI tests pass.
  • Manual: hyperframes capture https://example.com -o /tmp/foo — works (was broken)
  • Manual: hyperframes capture --video <proj> --list — lists 9 entries
  • Manual: hyperframes capture --video <proj> --index 1 — downloads 1.8MB
  • Manual: hyperframes capture --video <proj> --index 1 (re-run) — EEXIST skip
  • Manual: hyperframes capture --video <proj> --index 999 — rejects with available indices
  • Manual: hyperframes capture (no args) — Missing URL + exit 1
  • bunx oxlint clean
  • bunx oxfmt --check clean

… `--video` flag

PR #1447 added `capture video` as a citty subCommand. citty's runCommand
(node_modules/.bun/citty@0.2.2/.../dist/index.mjs:209-227) treats any non-flag
positional as a subcommand-name attempt and throws E_UNKNOWN_COMMAND when it
doesn't match — there's no fallback to the parent's positional args, so
`hyperframes capture https://vercel.com` died with "Unknown command https://vercel.com".

Per James's suggestion, surface video-download as `capture --video <project>`
(a mode flag) instead of a subcommand. Citty has no issue with a positional
URL coexisting with flags. `video.ts` now exports `runVideoMode()` instead of
a `defineCommand` default export.

- `hyperframes capture <url>` works again
- `hyperframes capture --video <project> --index N` downloads video
- `hyperframes capture --video <project> --list` lists manifest
- `hyperframes capture --video <project> --video-url <url>` downloads by URL

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strengths:

  • capture.ts:73–81 — the dispatch logic is crisp: one if (args.video) guard, clean import, early return. Dead simple to follow.
  • video.ts — the // fallow-ignore-next-line complexity directive moved correctly to the exported function (line 171). Byte-identical logic preservation is well-executed.
  • --video-url naming (instead of --url) is the right call; the PR body correctly explains citty's rejection of name collisions.

Review:

No blockers found.

  • nit capture.ts:62 — the "video-url" description says "Pair with --index, --video-url, or --list" (redundant self-reference). Minor copy issue.
  • nit video.ts:176–178VideoModeArgs.url field comment says "Exact video URL… (must match a manifest entry)" but that phrasing was already in the old subcommand. No need to address; just noting it's preserved as-is.

CI: All required checks green. Windows jobs (Render, Tests) pass on main — the two pending entries in CI are unrelated infra jobs that pass on main. regression-shards is skipping (expected for a CLI-only diff). No CI concerns.

Audited: packages/cli/src/commands/capture.ts (full), packages/cli/src/commands/capture/video.ts (full), packages/cli/src/commands/capture/video.test.ts (grep-audited for test coverage of renamed exports).


Verdict: APPROVE
Reasoning: Clean refactor — subcommand replaced by mode flag, all 22 unit tests pass, CLI smoke passes, behavior preserved byte-for-byte. The citty root-cause analysis is correct and the fix is minimal.

— Magi (AI reviewer)

@ukimsanov ukimsanov merged commit 16a3d24 into main Jun 15, 2026
35 checks passed
@ukimsanov ukimsanov deleted the fix/capture-video-flag branch June 15, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants