mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(cli): install the published skill set, not every SKILL.md in the repo (#3636)
Bare `hyperframes skills` passed `--skill '*'` to the upstream installer, which discovers every SKILL.md in the clone, so a full install put 26 skills on disk against the 20 the manifest publishes (the six repo-internal ones under .claude/skills / .agents/skills). It now resolves the canonical manifest and installs its names, the same path `skills update` uses; offline it warns and degrades to the pinned core set instead of the wildcard. Docs point the full set at `npx hyperframes skills` and say what `skills add --all` really pulls.
This commit is contained in:
@@ -8,7 +8,8 @@ This repo ships AI agent skills via [vercel-labs/skills](https://github.com/verc
|
||||
|
||||
```bash
|
||||
npx hyperframes skills update # default: installs/refreshes the core set — workflows install on demand
|
||||
npx skills add heygen-com/hyperframes # interactive picker (terminal only — non-interactive without --skill installs everything)
|
||||
npx hyperframes skills # all 20 published skills at once
|
||||
npx skills add heygen-com/hyperframes # interactive picker (terminal only; --all also pulls the repo-internal skills under .claude/skills)
|
||||
```
|
||||
|
||||
**Creation workflows** route through one entry skill — read `/hyperframes` first: it orients you to the whole surface, confirms the brief up front (the intent layer), and maps "make me a…" intent — usually a video, but also a navigable deck (`/slideshow`) or a composition port (`/remotion-to-hyperframes`) — to a concrete workflow. Consult it before invoking a specific workflow:
|
||||
|
||||
@@ -8,8 +8,8 @@ This repo ships 20 AI agent skills via [vercel-labs/skills](https://github.com/v
|
||||
|
||||
```bash
|
||||
npx hyperframes skills update # default: installs/refreshes the core set — workflows install on demand
|
||||
npx skills add heygen-com/hyperframes # interactive picker (terminal only — non-interactive without --skill installs all 20)
|
||||
npx skills add heygen-com/hyperframes --all # all 20 at once — only on explicit request
|
||||
npx hyperframes skills # all 20 published skills at once — only on explicit request
|
||||
npx skills add heygen-com/hyperframes # interactive picker (terminal only; --all also pulls the 6 repo-internal skills under .claude/skills)
|
||||
npx skills add heygen-com/hyperframes --skill <name> # just one (bare name, no leading slash)
|
||||
```
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Install the HyperFrames skills, then describe the video you want:
|
||||
npx skills add heygen-com/hyperframes
|
||||
```
|
||||
|
||||
> The picker opens with nothing pre-selected — the **Core Skills** group is all you need: the `/hyperframes` router installs each creation workflow on demand. Agents and non-interactive runs should use `npx hyperframes skills update` instead — it installs exactly the core set, whereas a non-interactive `skills add` without `--skill` installs all 20.
|
||||
> The picker opens with nothing pre-selected — the **Core Skills** group is all you need: the `/hyperframes` router installs each creation workflow on demand. Agents and non-interactive runs should use `npx hyperframes skills update` instead — it installs exactly the core set, whereas `skills add --all` installs every `SKILL.md` in the repo — the 20 published skills plus six repo-internal ones under `.claude/skills` / `.agents/skills`. For the full published set use `npx hyperframes skills`.
|
||||
>
|
||||
> `skills add` resolves the skills.sh registry blob, which can lag `main` by hours. `npx hyperframes skills update` installs from the current `main`, so reach for it when you need the newest copy of a skill.
|
||||
|
||||
|
||||
@@ -110,12 +110,14 @@ You can invoke a workflow directly when you already know it is the right one, bu
|
||||
|
||||
## Install more only when you need it
|
||||
|
||||
Install the complete set deliberately with:
|
||||
Install the complete published set deliberately with:
|
||||
|
||||
```bash
|
||||
npx skills add heygen-com/hyperframes --all
|
||||
npx hyperframes skills
|
||||
```
|
||||
|
||||
(`npx skills add heygen-com/hyperframes --all` also works, but it installs every `SKILL.md` in the repository, including repo-internal skills that are not part of the published set.)
|
||||
|
||||
Or install one named skill:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -72,7 +72,7 @@ The installer shows a picker. Select the **core skills** below — every project
|
||||
| `/figma` | A Figma file / frame / URL → imported assets, brand tokens, and reconstructed motion |
|
||||
|
||||
<Tip>
|
||||
To skip the picker and install everything (core + every workflow) in one shot, run `npx skills add heygen-com/hyperframes --all`. And start HyperFrames prompts with `/hyperframes` (or invoke the skill another way for non-Claude agents) — it loads the routing + composition context explicitly so the agent picks the right workflow and gets the rules right the first time.
|
||||
To skip the picker and install everything (core + every workflow) in one shot, run `npx hyperframes skills`. And start HyperFrames prompts with `/hyperframes` (or invoke the skill another way for non-Claude agents) — it loads the routing + composition context explicitly so the agent picks the right workflow and gets the rules right the first time.
|
||||
</Tip>
|
||||
|
||||
|
||||
|
||||
@@ -240,7 +240,11 @@ describe("hyperframes skills", () => {
|
||||
"add",
|
||||
"https://github.com/heygen-com/hyperframes",
|
||||
"--skill",
|
||||
"*",
|
||||
"hyperframes",
|
||||
"--skill",
|
||||
"hyperframes-core",
|
||||
"--skill",
|
||||
"pr-to-video",
|
||||
...GLOBAL_ARGS_TAIL,
|
||||
],
|
||||
],
|
||||
@@ -253,7 +257,11 @@ describe("hyperframes skills", () => {
|
||||
"add",
|
||||
"https://github.com/heygen-com/hyperframes",
|
||||
"--skill",
|
||||
"*",
|
||||
"hyperframes",
|
||||
"--skill",
|
||||
"hyperframes-core",
|
||||
"--skill",
|
||||
"pr-to-video",
|
||||
...GLOBAL_ARGS_TAIL,
|
||||
],
|
||||
],
|
||||
@@ -270,7 +278,11 @@ describe("hyperframes skills", () => {
|
||||
"add",
|
||||
"https://github.com/heygen-com/hyperframes",
|
||||
"--skill",
|
||||
"*",
|
||||
"hyperframes",
|
||||
"--skill",
|
||||
"hyperframes-core",
|
||||
"--skill",
|
||||
"pr-to-video",
|
||||
...GLOBAL_ARGS_TAIL,
|
||||
],
|
||||
],
|
||||
@@ -799,6 +811,30 @@ describe("hyperframes skills update <names>", () => {
|
||||
expect(await commandExitCode()).toBe(0);
|
||||
});
|
||||
|
||||
it("bare `skills` offline never falls back to the wildcard: warns and installs the pinned core set", async () => {
|
||||
setPlatform("linux");
|
||||
const { checkSkills, presentSkills, FALLBACK_CORE_SKILLS } =
|
||||
await import("../utils/skillsManifest.js");
|
||||
const clack = await import("@clack/prompts");
|
||||
vi.mocked(clack.log.warn).mockClear();
|
||||
vi.mocked(checkSkills).mockRejectedValue(new Error("offline"));
|
||||
vi.mocked(presentSkills)
|
||||
.mockImplementationOnce(() => [])
|
||||
.mockImplementation((names: readonly string[]) => [...names]);
|
||||
|
||||
const { default: skillsCmd } = await import("./skills.js");
|
||||
await skillsCmd.run?.({ args: {}, rawArgs: [], cmd: skillsCmd } as never);
|
||||
|
||||
const args = state.spawnCalls[0]?.args ?? [];
|
||||
// The upstream `*` would rediscover the repo-internal skills (26 vs 20).
|
||||
expect(skillFlagValues(args)).not.toContain("*");
|
||||
expect(skillFlagValues(args).sort()).toEqual([...FALLBACK_CORE_SKILLS].sort());
|
||||
expect(vi.mocked(clack.log.warn)).toHaveBeenCalledWith(
|
||||
expect.stringContaining("published skill set"),
|
||||
);
|
||||
expect(await commandExitCode()).toBe(0);
|
||||
});
|
||||
|
||||
// The `check || update` CI contract: offline, a bare update can't verify
|
||||
// freshness — exiting 0 would let the chain pass while everything stays
|
||||
// stale. It must fail loudly instead.
|
||||
|
||||
@@ -301,7 +301,12 @@ export interface UpdateSkillsResult {
|
||||
* - the requested names (a workflow being routed to, e.g. `pr-to-video`),
|
||||
* - the core set (entry router + shared domain skills — see skillsManifest),
|
||||
* - with `refreshInstalled`, whatever is already installed (refreshed, so an
|
||||
* update never *expands* a deliberate partial install).
|
||||
* update never *expands* a deliberate partial install),
|
||||
* - with `all`, every skill the manifest publishes. The upstream `*` wildcard
|
||||
* is not used on any path: it also sweeps up the repo-internal skills under
|
||||
* `.claude/skills` / `.agents/skills` (26 installed vs 20 published,
|
||||
* observed 2026-09-04). Offline, where the published set is unknowable, the
|
||||
* full install warns and degrades to the pinned core set instead.
|
||||
*
|
||||
* Only targets that are actually missing or outdated are passed to
|
||||
* `skills add` (one spawn, one `--skill` flag per name); when everything is
|
||||
@@ -313,6 +318,8 @@ export async function updateSkills(
|
||||
opts: {
|
||||
requested?: readonly string[];
|
||||
refreshInstalled?: boolean;
|
||||
/** Every skill the manifest publishes (bare `hyperframes skills`). */
|
||||
all?: boolean;
|
||||
strict?: boolean;
|
||||
cwd?: string;
|
||||
} = {},
|
||||
@@ -347,7 +354,19 @@ export async function updateSkills(
|
||||
}
|
||||
check = null; // manifest unreachable (offline / rate-limited) — presence mode below
|
||||
}
|
||||
if (!check) return updateSkillsOffline(requested, { strict, cwd: opts.cwd });
|
||||
if (!check) {
|
||||
if (opts.all) {
|
||||
// The published set is unknowable offline. Say so and degrade to the
|
||||
// pinned core set — never the upstream wildcard, which would quietly
|
||||
// reinstate the 26-skill sweep this path exists to avoid.
|
||||
clack.log.warn(
|
||||
c.warn(
|
||||
"Can't resolve the published skill set (manifest unreachable) — installing the pinned core set only. Re-run `hyperframes skills` online for the full set.",
|
||||
),
|
||||
);
|
||||
}
|
||||
return updateSkillsOffline(requested, { strict, cwd: opts.cwd });
|
||||
}
|
||||
|
||||
// "removed" entries are lock-attributed leftovers, not manifest skills —
|
||||
// they are `skills update`'s prune concern, never an update target.
|
||||
@@ -365,6 +384,7 @@ export async function updateSkills(
|
||||
|
||||
const targets = manifestSkills.filter(
|
||||
(s) =>
|
||||
opts.all === true ||
|
||||
requested.includes(s.name) ||
|
||||
isCoreSkill(s.name) ||
|
||||
(opts.refreshInstalled === true && s.status !== "missing"),
|
||||
@@ -785,7 +805,7 @@ export default defineCommand({
|
||||
// the positional so bare `hyperframes skills` installs, while
|
||||
// `hyperframes skills check|update` does not also re-install.
|
||||
if (!args._?.[0]) {
|
||||
await installSkills("*");
|
||||
await updateSkills({ all: true });
|
||||
// Same as updateSkills: a full install supersedes the background
|
||||
// nudge's cached pre-install verdict.
|
||||
invalidateSkillsCache();
|
||||
|
||||
Reference in New Issue
Block a user