Commit Graph

13 Commits

Author SHA1 Message Date
James 5ed196c53a refactor: address simplify review feedback on registry module
Applied a pass of review feedback that concentrates on correctness,
shared constants, and cleanup.

- Lift ITEM_TYPE_DIRS to @hyperframes/core/registry. Replaces an
  exhaustiveness-fragile switch in remote.ts and the hardcoded
  "examples" literal in scripts/generate-registry-items.ts. One
  constant, three consumers, checked against the ItemType union.
- remote.ts readCache: drop existsSync pre-check (TOCTOU double
  syscall) and rely on the existing try/catch for cache miss.
- templates/remote.ts: hoist the listRegistryItems/loadAllItems
  dynamic import to static — had no reason to be async-lazy.
- resolver.ts loadAllItems: accept an optional onWarn callback
  instead of calling console.warn directly. Default writes to stderr
  with a "hyperframes:registry" prefix so structured output (JSON,
  clack prompts) can opt in to silence.
- Scrub PR-number references from inline comments in the registry
  and compat-shim files. Intent language instead ("future item types",
  "compat shim for legacy init.ts callers").
- Fix stale test description in remote.test.ts that claimed PR 3
  renamed MANIFEST_FILENAME to registry.json (the rename didn't
  happen — the filename stays templates.json for the compat shim).

Skipped (documented as intentional in PR thread):
- Lifting assertSafeTarget to @hyperframes/core — CLI-specific
  concern, keeps core lean
- Extracting readCache/writeCache to utils/cache.ts — one consumer
  today; revisit when the CLI gets a second
- Hashing the cache-key slug — theoretical collision for a single-
  digit registry count; revisit when PR 14 adds custom registries
- Removing assertSafeTarget's layered checks — reviewer confirmed
  defense-in-depth is worth keeping for diagnostic clarity

Core: 452 tests pass. CLI: 70 tests pass (4 pre-existing failures
unchanged, unrelated to this PR). Format + lint clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 03:22:25 +00:00
James c5f0ab3f76 feat(cli): registry resolver + installer
PR 3/17 of the catalog system rollout. Introduces the registry
resolver/installer abstraction that the add command (PR 5) and future
block/component PRs will build on. No UX change — init --template still
works.

## What

- `packages/cli/src/registry/` — new module with 3 pieces:
  - remote.ts: fetches manifests (registry.json, registry-item.json) and
    individual files from a GitHub-hosted registry. Caches manifests for
    24h; item files go straight to destDir.
  - resolver.ts: listRegistryItems, loadAllItems (parallel fetch for the
    picker UX), resolveItem (single-item fetch with Available-list error).
  - installer.ts: assertSafeTarget (path-traversal guard) + installItem
    (parallel file download with up-front validation).
  - index.ts: barrel.
- `registry/registry.json` — new top-level manifest in the PR 1 shape
  (RegistryManifest). 8 items, all type=hyperframes:example.
- `registry/examples/<id>/registry-item.json` — per-item manifest for
  each of the 8 existing examples (RegistryItem / ExampleItem shape).
  Generated by scripts/generate-registry-items.ts by reading the legacy
  templates.json + probing each index.html for data-width/height/duration.
- `registry/examples/templates.json` — DELETED. Replaced by the above.
- `packages/cli/src/templates/{remote,generators}.ts` — now thin compat
  shims that delegate to the new registry module. Kept so existing init.ts
  imports still resolve; will be fully removed when add/init use the
  resolver directly.
- `scripts/generate-registry-items.ts` — one-off generator. Idempotent
  and supports --only <name> for adding future examples.

Tests: 13 new tests (8 resolver, 5 installer path-safety). 70 CLI tests
passing (was 57 on #253, +13). 4 pre-existing failures unchanged.

## Why

Without this abstraction every future PR (hyperframes add, seed blocks,
seed components, custom registries) has to keep piling onto the ad-hoc
fetch + cpSync pattern in fetchRemoteTemplate. The new module is the
single place that understands the registry wire format and the file
layout. PR 1 schema comes alive here.

## How

- Scope-trimmed from the plan: no transitive dep resolution (examples
  have no deps today — add for blocks/components in PR 5), no ajv schema
  validation (runtime safety via TS types + path-traversal guard;
  full schema validation lands when the registry starts serving
  third-party content).
- 24h cache on manifests keeps the picker snappy offline without needing
  N+1 fetches every run. Cache keyed by baseUrl so future custom
  registries (PR 14) don't collide with the default.
- Up-front target validation in installItem so a malformed item fails
  BEFORE any file is written — either all files land or none do.
- Compat shims preserve the init.ts contract
  (TemplateOption/RemoteTemplateInfo/fetchRemoteTemplate) so this PR
  doesn't have to touch init.ts yet. Init's refactor happens alongside
  the add command in PR 5 where it's part of a larger UX pass.
- Generator stays in-repo for future example additions (--only <name>).

## Test plan

- [x] bun run test in packages/cli: 70 passed (was 57, +13). 4 pre-existing
      failures (SRT/VTT whisper normalizer + lintProject clean-project)
      unchanged.
- [x] Unit tests for resolver: list/filter, parallel load with fail-safe,
      resolve-by-name with Available-list error, unreachable-registry
      error.
- [x] Unit tests for installer: accepts simple relative paths, rejects
      .. segments, rejects Unix absolute, rejects Windows drive letters,
      permits . no-op segments and dotfile-like names.
- [x] Smoke test: hyperframes init /tmp/x --template blank (bundled,
      unchanged code path) works end-to-end.
- [x] bunx oxfmt + bunx oxlint on changed files: clean.
- [x] Pre-commit typecheck (core + studio): clean.
- [ ] Smoke test remote fetch (--template warm-grain) — verifiable only
      post-merge; registry paths live on main after this PR lands.

## Breaking / migration

No end-user-visible UX change. init --template <name> still works the
same way. The MAIN internal change is that templates.json is gone from
registry/examples/ and the CLI now reads registry.json +
registry-item.json per example. Installed CLIs on older versions
(hyperframes@0.1.0 through 0.3.0) already broke at PR 2 merge (see
#253 breaking-change note). After this PR lands, the next CLI release
(0.3.1 or later) provides the full fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 03:22:25 +00:00
James Russo 69d9f08061 refactor: migrate templates/ → registry/examples/ (#253)
## What

PR 2/17 of the catalog system rollout. **Physical directory rename.** Stacks on #252.

- `git mv templates/ registry/examples/` — all 8 example directories (`decision-tree`, `kinetic-type`, `nyt-graph`, `play-mode`, `product-promo`, `swiss-grid`, `vignelli`, `warm-grain`) plus `templates.json`
- `packages/cli/src/templates/remote.ts` — `TEMPLATES_DIR` constant from `"templates"` → `"registry/examples"`, exported for regression testing
- `scripts/generate-template-previews.ts` — `remoteTemplatesDir` resolved to the new path
- Comment updates in `packages/cli/src/templates/generators.ts` and `packages/cli/src/commands/init.ts`
- New regression test `packages/cli/src/templates/remote.test.ts` pinning the path constants so future reverts fail a test instead of silently breaking installed CLIs

Design doc: [Hyperframes Catalog System](https://www.notion.so/heygen/Hyperframes-Catalog-System-Design-Plan-341449792c69813f899dcd53b4c0383a).

## Why

The current `templates/` directory is a flat "things that scaffold projects" bucket. The catalog model splits content into three tiers: **examples** (full projects — what today's templates are), **blocks** (sub-compositions), and **components** (effect snippets). `registry/examples/` is the canonical home for what was previously at `templates/`, and this PR makes room for `registry/blocks/` and `registry/components/` in future PRs without top-level clutter.

## How

- `git mv` preserves file history — GitHub renders these as renames, not deletions + additions.
- Remote template fetch via giget reads `TEMPLATES_DIR`, so updating that one constant is sufficient for the CLI's remote code path.
- The CLI's **internal** `packages/cli/src/templates/` directory (which holds the `blank` and `_shared` bundled assets plus `generators.ts`/`remote.ts`) is a separate concept and is **not** touched here. Renaming that module belongs to PR 3 where the abstraction changes to a registry resolver.
- `templates.json` keeps its existing shape and location (now at `registry/examples/templates.json`). **PR 3 will transform it** to the new `registry.json` shape introduced in PR 1 and generate a per-item `registry-item.json` for each example. Leaving the shape change to PR 3 keeps this PR a pure physical move.

## ⚠️ Breaking change for previously-installed CLIs (`hyperframes@0.1.0` – `0.3.0`)

**What happens:** every published CLI version has `TEMPLATES_DIR = "templates"` baked in. After this PR lands on `main`, those CLIs will 404 on:

- `raw.githubusercontent.com/heygen-com/hyperframes/main/templates/templates.json` (manifest list) — caught silently in `listRemoteTemplates`, so the template picker falls back to showing only `blank`
- `github:heygen-com/hyperframes/templates/<id>#main` (giget download) — raises "Template downloaded but missing index.html"

**Decision: accept the break.** Hyperframes is pre-1.0 OSS with a small installed base; complex mitigations (dual-path fetch, redirect stubs, manifest-at-old-path with empty array) add permanent maintenance cost for a one-time rename.

**Rollout plan:**

1. Merge #252 (PR 1 — types & schemas) first
2. Merge this PR (#253)
3. Ship a patched CLI release (`hyperframes@0.3.1`) in the same work-day. Already-pinned old CLIs break on remote examples, but upgrading restores full functionality
4. Note the break in release notes + `CHANGELOG.md` under the `0.3.1` entry

Users still on an older CLI will see the failure only if they invoke `hyperframes init` with `--template <non-blank>`; `--template blank` (bundled) continues to work offline on every version.

## Test plan

- [x] `bun run test` in `packages/cli`: **57 passed** (was 55 on main, +2 regression tests for the path constants). Same 4 pre-existing failures (SRT/VTT whisper normalizer + `lintProject` clean-project test) — unchanged from main. No regressions
- [x] **Manual smoke test**: `hyperframes init /tmp/x --template blank` works (bundled code path, unchanged)
- [x] `bunx oxfmt --check` + `bunx oxlint`: clean
- [x] `bun run typecheck` (core + studio, pre-commit hook): clean
- [ ] **Manual smoke test for remote fetch (`--template warm-grain`)** — not verifiable locally before merge. Remote fetch resolves `github:heygen-com/hyperframes/registry/examples/<id>#main`, which doesn't exist until this PR lands. Will work on `main` immediately after merge.

## Breaking / migration

- Internal repo path changes only. `--template` CLI flag continues to accept the same template names.
- See "Breaking change for previously-installed CLIs" above — decision is to ship a simultaneous CLI release rather than add a compat shim.

## Commits

1. `d691bd1` — initial rename + CLI path constant update
2. `fc0c642` — review feedback: docstring fix, regression tests, clarifying comment in `init.ts`, export constants for testing

## Stacks on

#252 — base branch. When #252 merges, this rebases onto `main`.

## Next in stack

PR 3 — `feat(cli): registry resolver + installer`. Transforms `templates.json` to the new `registry.json` shape (from PR 1's schema), generates `registry-item.json` for every existing example, introduces `packages/cli/src/registry/{resolver,installer,remote}.ts`, renames the `packages/cli/src/templates/` CLI module, and refactors `init` to call through the new abstraction.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-13 20:21:23 -07:00
James Russo e6a38c9e0f feat(ci): add alpha/beta/rc pre-release support to publish workflow (#167) 2026-03-31 14:16:57 -07:00
James Russo 6b1463fd5b refactor(cli): move templates to templates/ for remote fetching (#161)
* refactor(cli): move templates to examples/ for remote fetching

* refactor(cli): rename examples/ to templates/ for clarity

Follows Remix/Vite convention — these are init scaffolds, not general examples.
2026-03-31 13:10:04 -07:00
James Russo fee51f7a65 feat(docs): add template gallery page with visual previews (#160)
* feat(docs): add template gallery page with visual previews

* fix(docs): remove invalid MDX heading anchors

* chore: retrigger CI

* feat(docs): merge gallery into templates page with hover-to-play video previews

- Consolidated gallery.mdx and templates.mdx into single templates.mdx
- Moved templates page to Getting Started section
- Added MP4 video previews rendered by hyperframes (hover to play)
- Custom JS for hover-to-play behavior (Mintlify strips JSX event handlers)
- 2-column grid for landscape, 3-column for portrait
- Remotion-style cards with gradient overlay labels

* fix(docs): update broken links after templates page move

* ci(regression): remove scripts/ from regression trigger paths

scripts/ contains dev utilities (lint, versioning, preview generation)
that don't affect the rendering engine.
2026-03-31 13:04:04 -07:00
James Russo 05aceedd30 feat(docs): add template preview generation script (#159)
## What

Add a script that uses `@hyperframes/producer` to render PNG thumbnails of each built-in template. Output goes to `docs/images/templates/`.

## Why

User feedback: "I would have loved more visual examples of what's actually possible. I had to scaffold every template just to see what they look like." This is the foundation for a visual template gallery in the docs.

## How

- New `scripts/generate-template-previews.ts` uses the producer's `createFileServer` + `createCaptureSession` + `captureFrame` APIs — hyperframes renders its own templates
- Patches out `__VIDEO_SRC__` placeholders (same logic as `init.ts`) so templates render without a video file
- Captures a frame at t=2s for each template (skips `blank` — it's just empty scaffolding)
- Handles varying dimensions (vignelli is 1080x1920 portrait)
- Adds `pnpm generate:previews` npm script

## Test plan

- [x] `pnpm generate:previews` generates 8 PNGs in `docs/images/templates/`
- [x] Each PNG is visually correct (verified by viewing)
- [x] `--only <template>` flag works for single template generation
2026-03-31 14:23:11 -04:00
James Russo a9d49cd528 fix(cli): auto-copy all templates to dist and add skill lint (#153)
- Replace hardcoded template list in build:copy with `cp -r src/templates/*`
  so new templates are included automatically (kinetic-type, decision-tree,
  product-promo, nyt-graph were missing from published package)
- Fix captions SKILL.md: reword `!` and `>` in inline backticks that
  triggered Claude Code's bash permission checker
- Add scripts/lint-skills.ts to catch shell-unsafe patterns in SKILL.md
  files (runs as part of `bun run lint` in CI)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:33:54 -07:00
James Russo 24c4fa6041 fix: make set-version commit and tag by default (#143)
The --tag flag was optional, which led to v0.1.11 and v0.1.12 being
bumped without tags — skipping npm publish entirely. Invert the default:
always commit + tag, with --no-tag as the escape hatch.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:21:08 -07:00
Miguel Ángel e1c1c6fb30 fix: rewrite workspace deps before npm publish (#67)
## Summary
- rewrite workspace protocol dependencies to publish-safe semver ranges before the npm publish workflow runs
- keep workspace protocol references in source manifests for normal monorepo development
- ensure the published `@hyperframes/producer` manifest no longer ships unresolved `workspace:` deps

## Why
The internal repo hit a Docker build failure because the published `@hyperframes/producer` metadata still contained `workspace:^` dependencies for `@hyperframes/core` and `@hyperframes/engine`. `npm install` cannot resolve those outside the monorepo, so the published package itself was the root cause.

## Validation
- `bun install --frozen-lockfile`
- `bun run build:producer`
- `bun run prepare:publish-manifests`
- `npm pack --workspace packages/core`
- `npm pack --workspace packages/engine`
- `npm pack --workspace packages/producer`
- installed the three tarballs together in a clean temp project with `npm install --ignore-scripts`
- extracted the producer tarball and verified its `package.json` contains `^0.1.3` for `@hyperframes/core` and `@hyperframes/engine`, not `workspace:^`
2026-03-26 21:14:39 +01:00
Vance Ingalls 61c5257402 fix(ci): update publish workflow to use bun install (#36)
* fix(ci): update publish workflow to use bun install

pnpm-lock.yaml was removed in the bun migration but publish.yml
still referenced it. Use bun for install/build, keep pnpm for
publish (publishConfig overrides + --provenance).

* docs: update stale pnpm references to bun across docs and scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:46:58 -07:00
Vance Ingalls 20be2ea1c2 style: apply oxfmt baseline formatting across all source files (#25)
## Summary
- Run `oxfmt .` across the entire codebase to establish formatted baseline
- 299 files changed — mechanical formatting only, no logic changes
- Double quotes, semicolons, 2-space indent, trailing commas, 100 print width

Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits)

## Test plan
- [x] `pnpm format:check` — all 426 files pass
- [x] `pnpm -r typecheck` — all packages pass
- [x] `pnpm build` — all packages build
- [x] All 348 tests pass
2026-03-23 17:15:14 -07:00
James 306909534b ci: add tag-triggered npm publish workflow with OIDC provenance 2026-03-23 03:20:21 +00:00