Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
code: ${{ steps.filter.outputs.code }}
cli: ${{ steps.filter.outputs.cli }}
skills: ${{ steps.filter.outputs.skills }}
catalog_index: ${{ steps.filter.outputs.catalog_index }}
codex_plugin: ${{ steps.filter.outputs.codex_plugin }}
gcp_beginframe: ${{ steps.filter.outputs.gcp_beginframe }}
studio: ${{ steps.filter.outputs.studio }}
Expand All @@ -52,6 +53,10 @@ jobs:
with:
token: ""
filters: |
catalog_index:
- "registry/registry.json"
- "registry/catalog-artifact/**"
- "scripts/catalog/check-artifact-coverage.ts"
code:
- "packages/**"
- "scripts/**"
Expand Down Expand Up @@ -363,6 +368,21 @@ jobs:
# `gen:skills-manifest --check`, which compares per-skill content hashes; the
# manifest carries no version/timestamp, so it only fails on real content
# drift. bun runs the TS script directly, no install needed.
catalog-index-coverage:
name: "Catalog: search index covers the registry"
needs: changes
if: needs.changes.outputs.catalog_index == 'true'
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
# Comparing two name lists needs neither the embedding model nor a
# network call, so this stays a seconds-long gate. Regenerating the
# vectors does need the model, which is why CI checks rather than fixes.
- name: Verify every searchable registry item has a vector
run: bun scripts/catalog/check-artifact-coverage.ts

skills-manifest:
name: "Skills: manifest in sync"
needs: changes
Expand Down
33 changes: 29 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,36 @@ Blocks don't need `demo.html` — they are already standalone compositions.

### Checklist for new items

**Anyone can add an item.** Nothing here needs commit access, and the two steps
that do need something a contributor may not have are handled by a maintainer
before merge, listed at the end.

1. Create `registry/<blocks|components>/<name>/registry-item.json` following the [schema](packages/core/schemas/registry-item.json)
2. Add the item to `registry/registry.json`
3. For components: include a `demo.html`
4. Run `npx hyperframes lint` and `npx hyperframes validate` on your HTML
5. Test the install flow: `hyperframes add <name> --dir /tmp/test-project`
2. For components: include a `demo.html`
3. Run `npx hyperframes lint` and `npx hyperframes validate` on your HTML
4. Test the install flow: `hyperframes add <name> --dir /tmp/test-project`
5. Regenerate the manifest: `npx tsx scripts/generate-registry-items.ts`

`registry/registry.json` is generated from the item directories, so edit it with
that script rather than by hand. An entry added by hand survives until the next
regeneration and then disappears; entries left behind for directories that no
longer exist are worse, because `hyperframes add <name>` resolves the name and
then fails on missing files.

### What a maintainer finishes for you

Two things need assets an outside contributor is not expected to install. Open
the pull request without them and say so; neither blocks review.

| Thing | If you have it | If you do not |
| ----------------------------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------- |
| The search index (`registry/catalog-artifact/`) | The pre-commit hook rebuilds and stages it | The hook skips, CI names the gap, a maintainer regenerates before merge |
| The catalog preview image | Internal contributors run `scripts/upload-docs-images.sh` | Attach the preview MP4 to the PR instead |

The search index needs a 32 MB embedding model, which is an opt-in for catalog
search rather than a build dependency. Until it is regenerated your item is
findable by word search and not by meaning, which is the same state as any item
published since a user last refreshed their copy.

### Auto-generated docs

Expand Down
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions docs/schema/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@
"format": "uri",
"description": "Registry homepage URL."
},
"catalogArtifact": {
"type": "object",
"description": "Published on-device vector artifact for this registry.",
"required": ["revision"],
"additionalProperties": false,
"properties": {
"revision": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA-256 identity of the searchable corpus and embedding contract."
}
}
},
"items": {
"type": "array",
"description": "Items in this registry. Each entry is a shorthand reference; the full item manifest lives at <type-dir>/<name>/registry-item.json.",
Expand Down
13 changes: 13 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ pre-commit:
# enforces the same via the "Skills: manifest in sync" job). Churn-free:
# the generator rewrites only when a content hash actually changed.
run: bun packages/cli/scripts/gen-skills-manifest.ts && git add skills-manifest.json
catalog-index:
glob: "registry/*/*/registry-item.json"
# Rebuild the on-device search vectors when an item's searchable text
# changes, then re-stage them so registry/catalog-artifact/ never drifts
# from the registry (CI enforces the same via the "Catalog: search index
# covers the registry" job). Churn-free: identical inputs re-embed to
# identical bytes, so an unrelated registry edit leaves no diff.
# Exit 3 is "no embedding model here", which is the normal case for an
# outside contributor. Their commit must not be blocked over a 32 MB
# opt-in they were never asked to install; CI names the gap instead.
run: |
bun scripts/catalog/build-local-vectors.ts || { [ $? -eq 3 ] && exit 0; exit 1; }
git add registry/registry.json registry/catalog-artifact/local-vectors.json registry/catalog-artifact/local-vectors.bin
typecheck:
glob: "*.{ts,tsx}"
run: cd packages/core && bunx tsc --noEmit && cd ../studio && bunx tsc --noEmit && cd ../.. && bunx tsc --noEmit -p scripts/tsconfig.json
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"player:perf": "bun run --filter @hyperframes/player perf",
"format:check": "oxfmt --check .",
"knip": "knip",
"test:scripts": "node --import tsx --test scripts/check-tracked-artifacts.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/publish-workflow.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/lint-skills.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs",
"test:scripts": "node --import tsx --test scripts/check-tracked-artifacts.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/publish-workflow.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/lint-skills.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs && vitest run scripts/catalog/",
"typecheck:scripts": "tsc --noEmit -p scripts/tsconfig.json",
"test:skills": "node --test 'skills/**/*.test.mjs'",
"generate:previews": "tsx scripts/generate-template-previews.ts",
Expand All @@ -72,6 +72,7 @@
"oxlint": "^1.56.0",
"tsx": "^4.21.0",
"typescript": "^5.0.0",
"vitest": "^3.2.4",
"yaml": "^2.9.0"
},
"resolutions": {
Expand Down
Loading
Loading