mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
feat(skills): add hyperframes-cli skill (#154)
* feat(skills): add hyperframes-cli skill for CLI workflow guidance Adds a new skill that teaches AI agents how to use the HyperFrames CLI (init, lint, dev, render, doctor). Previously, agents had no way to discover the CLI — the compose-video skill only covered HTML authoring. This led to agents searching for binaries, finding the monorepo, and running bun run studio manually instead of using npx hyperframes dev. Also registers the skill in init.ts so new projects get it bundled alongside hyperframes-compose and hyperframes-captions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(cli): rename dev command to preview The command starts a preview server — "preview" describes what users are doing more accurately than "dev". Updates the command name, file name, all CLI references, docs, skills, and template CLAUDE.md. 22 files updated across CLI source, docs, skills, and templates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): replace stale dev reference with preview in CLI skill Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(docs): catch remaining dev references missed in rename - testing-local-changes.mdx: two inline command examples - troubleshooting.mdx: anchor link #dev → #preview, "dev server" → "preview server" - cli.mdx: "dev server" → "preview server" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
bc956bb6da
commit
9cbfec1eca
@@ -18,7 +18,7 @@ import { checkForUpdate, printUpdateNotice } from "./utils/updateCheck.js";
|
||||
|
||||
const subCommands = {
|
||||
init: () => import("./commands/init.js").then((m) => m.default),
|
||||
dev: () => import("./commands/dev.js").then((m) => m.default),
|
||||
preview: () => import("./commands/preview.js").then((m) => m.default),
|
||||
render: () => import("./commands/render.js").then((m) => m.default),
|
||||
lint: () => import("./commands/lint.js").then((m) => m.default),
|
||||
info: () => import("./commands/info.js").then((m) => m.default),
|
||||
|
||||
@@ -398,7 +398,7 @@ function scaffoldProject(
|
||||
// Copy project-level skills (.claude/skills/) for immediate availability
|
||||
const skillsSrcDir = getBundledSkillsDir();
|
||||
if (existsSync(skillsSrcDir)) {
|
||||
const projectSkills = ["hyperframes-compose", "hyperframes-captions"];
|
||||
const projectSkills = ["hyperframes-compose", "hyperframes-captions", "hyperframes-cli"];
|
||||
for (const skill of projectSkills) {
|
||||
const src = join(skillsSrcDir, skill);
|
||||
if (existsSync(src)) {
|
||||
@@ -420,7 +420,7 @@ async function nextStepLoop(destDir: string): Promise<void> {
|
||||
message: "What do you want to do?",
|
||||
options: [
|
||||
{
|
||||
value: "dev",
|
||||
value: "preview",
|
||||
label: "Open in studio",
|
||||
hint: "full editor with timeline",
|
||||
},
|
||||
@@ -437,9 +437,9 @@ async function nextStepLoop(destDir: string): Promise<void> {
|
||||
// Hand off to the selected command — use explicit imports so the
|
||||
// bundler can resolve them (dynamic import with a variable fails in bundles)
|
||||
try {
|
||||
if (next === "dev") {
|
||||
const devCmd = await import("./dev.js").then((m) => m.default);
|
||||
await runCommand(devCmd, { rawArgs: [destDir] });
|
||||
if (next === "preview") {
|
||||
const previewCmd = await import("./preview.js").then((m) => m.default);
|
||||
await runCommand(previewCmd, { rawArgs: [destDir] });
|
||||
} else if (next === "render") {
|
||||
const renderCmd = await import("./render.js").then((m) => m.default);
|
||||
await runCommand(renderCmd, { rawArgs: [destDir] });
|
||||
@@ -623,7 +623,7 @@ Examples:
|
||||
);
|
||||
console.log();
|
||||
console.log(` ${c.accent("2.")} Preview in the browser:`);
|
||||
console.log(` ${c.accent(`cd ${name}`)} && ${c.accent("npx hyperframes dev")}`);
|
||||
console.log(` ${c.accent(`cd ${name}`)} && ${c.accent("npx hyperframes preview")}`);
|
||||
console.log();
|
||||
console.log(` ${c.accent("3.")} Render to MP4 when ready:`);
|
||||
console.log(` ${c.accent(`cd ${name}`)} && ${c.accent("npx hyperframes render")}`);
|
||||
|
||||
@@ -59,22 +59,22 @@ async function serveWithPortFallback(
|
||||
}
|
||||
|
||||
export default defineCommand({
|
||||
meta: { name: "dev", description: "Start the studio for local development" },
|
||||
meta: { name: "preview", description: "Start the studio for previewing compositions" },
|
||||
args: {
|
||||
dir: { type: "positional", description: "Project directory", required: false },
|
||||
port: { type: "string", description: "Port to run the dev server on", default: "3002" },
|
||||
port: { type: "string", description: "Port to run the preview server on", default: "3002" },
|
||||
},
|
||||
async run({ args }) {
|
||||
const rawArg = args.dir;
|
||||
const dir = resolve(rawArg ?? ".");
|
||||
const startPort = parseInt(args.port ?? "3002", 10);
|
||||
|
||||
// Compute display name: preserve symlink/CWD name when user runs "hyperframes dev ."
|
||||
// Compute display name: preserve symlink/CWD name when user runs "hyperframes preview ."
|
||||
const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
|
||||
const projectName = isImplicitCwd ? basename(process.env.PWD ?? dir) : basename(dir);
|
||||
|
||||
// Lint before starting — surface issues for the agent to fix.
|
||||
// dev.ts doesn't use resolveProject() because it needs to proceed even without index.html.
|
||||
// preview.ts doesn't use resolveProject() because it needs to proceed even without index.html.
|
||||
const indexPath = join(dir, "index.html");
|
||||
if (existsSync(indexPath)) {
|
||||
const project = { dir, name: projectName, indexPath };
|
||||
@@ -137,7 +137,7 @@ async function runDevMode(dir: string, projectName?: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
clack.intro(c.bold("hyperframes dev"));
|
||||
clack.intro(c.bold("hyperframes preview"));
|
||||
|
||||
const s = clack.spinner();
|
||||
s.start("Starting studio...");
|
||||
@@ -240,7 +240,7 @@ async function runLocalStudioMode(dir: string, projectName?: string): Promise<vo
|
||||
}
|
||||
}
|
||||
|
||||
clack.intro(c.bold("hyperframes dev") + c.dim(" (local studio)"));
|
||||
clack.intro(c.bold("hyperframes preview") + c.dim(" (local studio)"));
|
||||
const s = clack.spinner();
|
||||
s.start("Starting studio...");
|
||||
|
||||
@@ -304,7 +304,7 @@ async function runEmbeddedMode(
|
||||
const pName = projectName ?? basename(dir);
|
||||
const { app } = createStudioServer({ projectDir: dir, projectName: pName });
|
||||
|
||||
clack.intro(c.bold("hyperframes dev"));
|
||||
clack.intro(c.bold("hyperframes preview"));
|
||||
const s = clack.spinner();
|
||||
s.start("Starting studio...");
|
||||
|
||||
@@ -53,7 +53,7 @@ ${c.bold("SUBCOMMANDS:")}
|
||||
${c.accent("disable")} ${c.dim("Disable anonymous telemetry")}
|
||||
|
||||
${c.bold("WHAT WE COLLECT:")}
|
||||
${c.dim("\u2022")} Command names (init, render, dev, etc.)
|
||||
${c.dim("\u2022")} Command names (init, render, preview, etc.)
|
||||
${c.dim("\u2022")} Render performance (duration, fps, quality)
|
||||
${c.dim("\u2022")} Template choices
|
||||
${c.dim("\u2022")} OS, architecture, Node.js version, CLI version
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Embedded studio server for `hyperframes dev` outside the monorepo.
|
||||
* Embedded studio server for `hyperframes preview` outside the monorepo.
|
||||
*
|
||||
* Uses the shared studio API module from @hyperframes/core/studio-api,
|
||||
* providing a CLI-specific adapter for single-project, in-process rendering.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npx hyperframes dev # preview in browser (studio editor)
|
||||
npx hyperframes preview # preview in browser (studio editor)
|
||||
npx hyperframes render # render to MP4
|
||||
npx hyperframes lint # validate compositions (errors + warnings)
|
||||
npx hyperframes lint --verbose # include info-level findings
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface LintFormatOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format lint findings for console output. Used by lint, render, and dev commands.
|
||||
* Format lint findings for console output. Used by lint, render, and preview commands.
|
||||
*/
|
||||
export function formatLintFindings(
|
||||
{ results, totalErrors, totalWarnings, totalInfos }: ProjectLintResult,
|
||||
|
||||
Reference in New Issue
Block a user