Files
JamesandClaude Opus 4.6 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
..