feat(cli): prompt to install skills during init (#206)

Replace the static "Tip" message at the end of `hyperframes init` with an
interactive prompt that offers to install AI coding skills. When the user
accepts, the skills command runs `npx skills add` with `--all` and
`stdio: "inherit"` so the native installer output is visible.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
James Russo
2026-04-03 07:36:08 -07:00
committed by GitHub
co-authored by Claude Opus 4.6
parent e2c8ed5d83
commit 29541aefaa
2 changed files with 21 additions and 30 deletions
+13 -4
View File
@@ -692,10 +692,19 @@ export default defineCommand({
const files = readdirSync(destDir);
clack.note(files.map((f) => c.accent(f)).join("\n"), c.success(`Created ${name}/`));
clack.log.message(
`${c.dim("Tip:")} Install AI coding skills: ${c.accent("npx skills add heygen-com/hyperframes")}\n` +
`${c.dim(" Then open this project with")} ${c.accent("Claude Code")}${c.dim(",")} ${c.accent("Cursor")}${c.dim(", or your preferred agent.")}`,
);
// Offer to install AI coding skills
const installSkills = await clack.confirm({
message: "Install AI coding skills? (for Claude Code, Cursor, Codex, etc.)",
initialValue: true,
});
if (clack.isCancel(installSkills)) {
clack.cancel("Setup cancelled.");
process.exit(0);
}
if (installSkills) {
const skillsCmd = await import("./skills.js").then((m) => m.default);
await runCommand(skillsCmd, { rawArgs: [] });
}
// Auto-launch studio preview
clack.log.info("Opening studio preview...");
+8 -26
View File
@@ -14,12 +14,13 @@ function hasNpx(): boolean {
function runSkillsAdd(repo: string): Promise<void> {
return new Promise((resolve, reject) => {
const child = spawn("npx", ["skills", "add", repo, "--all", "-g"], {
stdio: "ignore",
const child = spawn("npx", ["skills", "add", repo, "--all"], {
stdio: "inherit",
timeout: 120_000,
});
child.on("close", (code) => {
child.on("close", (code, signal) => {
if (code === 0) resolve();
else if (signal === "SIGINT" || code === 130) process.exit(0);
else reject(new Error(`npx skills add exited with code ${code}`));
});
child.on("error", reject);
@@ -38,39 +39,20 @@ export default defineCommand({
},
args: {},
async run() {
clack.intro(c.bold("hyperframes skills"));
if (!hasNpx()) {
clack.log.error(c.error("npx not found. Install Node.js and retry."));
clack.outro(c.warn("No skills installed."));
return;
}
const installed: string[] = [];
const skipped: string[] = [];
for (const source of SOURCES) {
const spinner = clack.spinner();
spinner.start(`Installing ${source.name} skills...`);
console.log();
console.log(c.bold(`Installing ${source.name} skills...`));
console.log();
try {
await runSkillsAdd(source.repo);
installed.push(source.name);
spinner.stop(c.success(`${source.name} skills installed`));
} catch {
skipped.push(source.name);
spinner.stop(c.dim(`${source.name} skills skipped (unavailable)`));
console.log(c.dim(`${source.name} skills skipped`));
}
}
if (skipped.length > 0) {
console.log(` ${c.dim("Skipped:")} ${skipped.join(", ")}`);
console.log();
}
if (installed.length > 0) {
clack.outro(c.success(`${installed.join(" + ")} skills installed.`));
} else {
clack.outro(c.warn("No skills installed."));
}
},
});