Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ HyperFrames ships 20 skills agents load on demand. Read `/hyperframes` first —

Run `npx skills add heygen-com/hyperframes --full-depth` for the interactive picker, `npx skills add heygen-com/hyperframes --all --full-depth` to install all 20 at once (skips the picker), or `npx skills add heygen-com/hyperframes --skill <name> --full-depth` for just one (bare name, no leading `/`). Keep `--full-depth` — it installs the current `main`; without it `skills add` fetches the skills.sh blob, which lags by hours.

Installs stay lean after that: `npx hyperframes init` keeps the **core set** fresh (the router, the `hyperframes-*` domain skills, and `media-use` — plus whatever is already installed; `/figma` stays on demand) and never expands a partial install; the creation workflows install **on demand** — the router runs `npx hyperframes skills update <workflow>` before entering one. Nothing re-pulls the full set behind your back.

### Router

| Skill | Use when |
Expand Down
77 changes: 38 additions & 39 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,48 +577,46 @@ async function scaffoldProject(
}

/**
* Ensure the AI coding skills are present and current. Checks the installed
* skills against the latest published on GitHub and only (re)installs when
* something is outdated or missing — so re-running `init` on an up-to-date
* machine is a no-op. Best-effort: if the version check can't reach GitHub, it
* installs anyway. The install itself (`installAllSkills`) installs the full set
* once GLOBALLY (~/.claude/skills + ~/.agents/skills) and mirrors it into every
* other installed agent, so it is project-independent — the check is global-first
* to match.
* Keep the AI coding skills present and current — TARGETED, not the full
* set. Guarantees the core set (the `/hyperframes` entry router + shared
* domain skills) and refreshes any skill already installed; the end-user
* workflow skills are NOT pulled here — they install on demand when their
* workflow is triggered (`hyperframes skills update <name>`, which the router
* runs before entering a workflow). Re-running `init` on an up-to-date machine
* is a no-op, and `init` never expands a deliberate partial install.
* Best-effort: offline, it degrades to a presence check and never breaks init.
* The install itself lands once GLOBALLY (~/.claude/skills + ~/.agents/skills)
* and mirrors into every other installed agent, so it is project-independent —
* the check is global-first to match.
*/
async function ensureSkillsCurrent(destDir: string): Promise<void> {
const { installAllSkills } = await import("./skills.js");
const { checkSkills } = await import("../utils/skillsManifest.js");
async function keepSkillsCurrent(destDir: string): Promise<void> {
const { updateSkills } = await import("./skills.js");

console.log();
console.log(c.bold("Checking AI coding skills against GitHub..."));
let needsInstall = true;
// Wrap defensively (non-strict already swallows most failures): a
// skills-install failure can never break `init` itself — it warns and
// proceeds, since --skip-skills no longer escapes this path.
try {
const result = await checkSkills({ cwd: destDir });
needsInstall = result.updateAvailable;
} catch {
// Couldn't reach GitHub (offline, rate-limited) — install anyway.
}

if (needsInstall) {
// installAllSkills installs the full set once globally and mirrors it into
// every installed agent's global dir — project-independent, so a freshly
// scaffolded project doesn't need any agent folders yet.
//
// Best-effort: installAllSkills (non-strict here) already swallows its own
// failures, but now that --skip-skills no longer escapes this path every
// init runs it — including offline ones, where checkSkills throws and we
// fall through to "install anyway". Wrap defensively so a skills-install
// failure can never break `init` itself; it only warns and proceeds.
try {
await installAllSkills({ cwd: destDir });
} catch (err) {
const result = await updateSkills({ refreshInstalled: true, cwd: destDir });
if (result.presenceOnly) {
// Freshness never got checked (GitHub unreachable) — don't claim
// "up to date"; the engine already reported what it could verify or
// blind-install. Point at the recovery command instead.
console.log(
c.dim(`AI coding skills install skipped: ${err instanceof Error ? err.message : err}`),
c.dim("Skills freshness unverified — run `npx hyperframes skills update` when online."),
);
} else if (result.installed.length === 0) {
console.log(c.success("AI coding skills are already up to date."));
} else {
console.log(
c.dim("Workflow skills not installed here are added on demand, when first used."),
);
}
} else {
console.log(c.success("AI coding skills are already up to date."));
} catch (err) {
console.log(
c.dim(`AI coding skills install skipped: ${err instanceof Error ? err.message : err}`),
);
}
}

Expand Down Expand Up @@ -871,7 +869,7 @@ export default defineCommand({
}

if (!skipSkills) {
await ensureSkillsCurrent(destDir);
await keepSkillsCurrent(destDir);
}

console.log();
Expand Down Expand Up @@ -1087,11 +1085,12 @@ export default defineCommand({
const files = readdirSync(destDir);
clack.note(files.map((f) => c.accent(f)).join("\n"), c.success(`Created ${name}/`));

// Check skills against GitHub and (re)install only if outdated or missing —
// init is the one place the full set is pulled. The --skip-skills flag is
// temporarily neutered (see above); CI/tests opt out via HYPERFRAMES_SKIP_SKILLS=1.
// Check skills against GitHub and refresh only what's stale — the core set
// plus anything already installed; workflow skills install on demand. The
// --skip-skills flag is temporarily neutered (see above); CI/tests opt out
// via HYPERFRAMES_SKIP_SKILLS=1.
if (!skipSkills) {
await ensureSkillsCurrent(destDir);
await keepSkillsCurrent(destDir);
}

// Auto-launch studio preview
Expand Down
Loading
Loading