hyperframes 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -422,7 +422,7 @@ var VERSION;
422
422
  var init_version = __esm({
423
423
  "src/version.ts"() {
424
424
  "use strict";
425
- VERSION = true ? "0.1.6" : "0.0.0-dev";
425
+ VERSION = true ? "0.1.7" : "0.0.0-dev";
426
426
  }
427
427
  });
428
428
 
@@ -2748,6 +2748,25 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, rmSync
2748
2748
  import { join as join3, dirname } from "path";
2749
2749
  import { homedir as homedir3 } from "os";
2750
2750
  import { execFileSync as execFileSync2 } from "child_process";
2751
+ function hasNpx() {
2752
+ try {
2753
+ execFileSync2("npx", ["--version"], { stdio: "ignore", timeout: 5e3 });
2754
+ return true;
2755
+ } catch {
2756
+ return false;
2757
+ }
2758
+ }
2759
+ function runSkillsAdd(repo, agents, global) {
2760
+ const args = ["skills", "add", repo, "-y"];
2761
+ if (global) args.push("-g");
2762
+ for (const agent of agents) {
2763
+ args.push("-a", agent);
2764
+ }
2765
+ execFileSync2("npx", args, {
2766
+ stdio: "ignore",
2767
+ timeout: 12e4
2768
+ });
2769
+ }
2751
2770
  function hasGit2() {
2752
2771
  try {
2753
2772
  execFileSync2("git", ["--version"], { stdio: "ignore", timeout: 5e3 });
@@ -2764,6 +2783,7 @@ function gitClone(repo, dest) {
2764
2783
  });
2765
2784
  }
2766
2785
  function fetchRepo(source) {
2786
+ const gitUrl = `https://github.com/${source.repo}.git`;
2767
2787
  if (existsSync3(source.cache)) {
2768
2788
  try {
2769
2789
  execFileSync2("git", ["pull", "--ff-only"], {
@@ -2773,18 +2793,17 @@ function fetchRepo(source) {
2773
2793
  env: GIT_ENV
2774
2794
  });
2775
2795
  } catch {
2776
- const skillsDir = join3(source.cache, source.skillsPath);
2777
- if (existsSync3(skillsDir)) {
2778
- return skillsDir;
2779
- }
2796
+ const skillsDir2 = join3(source.cache, source.skillsPath);
2797
+ if (existsSync3(skillsDir2)) return skillsDir2;
2780
2798
  rmSync2(source.cache, { recursive: true, force: true });
2781
- gitClone(source.repo, source.cache);
2799
+ gitClone(gitUrl, source.cache);
2782
2800
  }
2783
2801
  } else {
2784
2802
  mkdirSync3(dirname(source.cache), { recursive: true });
2785
- gitClone(source.repo, source.cache);
2803
+ gitClone(gitUrl, source.cache);
2786
2804
  }
2787
- return join3(source.cache, source.skillsPath);
2805
+ const skillsDir = join3(source.cache, source.skillsPath);
2806
+ return existsSync3(skillsDir) ? skillsDir : void 0;
2788
2807
  }
2789
2808
  function installSkillsFromDir(sourceDir, targetDir, sourceName) {
2790
2809
  const installed = [];
@@ -2795,24 +2814,20 @@ function installSkillsFromDir(sourceDir, targetDir, sourceName) {
2795
2814
  const skillFile = join3(sourceDir, entry.name, "SKILL.md");
2796
2815
  if (!existsSync3(skillFile)) continue;
2797
2816
  const destDir = join3(targetDir, entry.name);
2798
- const overwritten = existsSync3(destDir);
2799
- if (overwritten) rmSync2(destDir, { recursive: true, force: true });
2817
+ if (existsSync3(destDir)) rmSync2(destDir, { recursive: true, force: true });
2800
2818
  mkdirSync3(destDir, { recursive: true });
2801
2819
  cpSync(join3(sourceDir, entry.name), destDir, { recursive: true });
2802
- installed.push({ name: entry.name, source: sourceName, overwritten });
2820
+ installed.push({ name: entry.name, source: sourceName });
2803
2821
  }
2804
2822
  return installed;
2805
2823
  }
2806
- async function installAllSkills(targetNames) {
2807
- if (!hasGit2()) return { count: 0, targets: [], skipped: SOURCES.map((s) => s.name) };
2808
- const targets = targetNames ? TARGETS.filter((t2) => targetNames.includes(t2.flag)) : TARGETS.filter((t2) => t2.defaultEnabled);
2809
- let totalCount = 0;
2824
+ function fallbackInstall(targets) {
2810
2825
  const skipped = [];
2811
2826
  const fetched = [];
2812
2827
  for (const source of SOURCES) {
2813
2828
  try {
2814
2829
  const skillsDir = fetchRepo(source);
2815
- if (existsSync3(skillsDir)) {
2830
+ if (skillsDir) {
2816
2831
  fetched.push({ source, skillsDir });
2817
2832
  } else {
2818
2833
  skipped.push(source.name);
@@ -2821,21 +2836,45 @@ async function installAllSkills(targetNames) {
2821
2836
  skipped.push(source.name);
2822
2837
  }
2823
2838
  }
2824
- const [firstTarget, ...remainingTargets] = targets;
2825
- if (firstTarget) {
2826
- mkdirSync3(firstTarget.dir, { recursive: true });
2839
+ const [first, ...rest] = targets;
2840
+ const allInstalled = [];
2841
+ if (first) {
2842
+ mkdirSync3(first.dir, { recursive: true });
2827
2843
  for (const { skillsDir, source } of fetched) {
2828
- const skills = installSkillsFromDir(skillsDir, firstTarget.dir, source.name);
2829
- totalCount += skills.length;
2844
+ allInstalled.push(...installSkillsFromDir(skillsDir, first.dir, source.name));
2830
2845
  }
2831
2846
  }
2832
- for (const target of remainingTargets) {
2847
+ for (const target of rest) {
2833
2848
  mkdirSync3(target.dir, { recursive: true });
2834
2849
  for (const { skillsDir, source } of fetched) {
2835
2850
  installSkillsFromDir(skillsDir, target.dir, source.name);
2836
2851
  }
2837
2852
  }
2838
- return { count: totalCount, targets: targets.map((t2) => t2.name), skipped };
2853
+ return { count: allInstalled.length, installed: allInstalled, skipped };
2854
+ }
2855
+ async function installAllSkills(targetNames) {
2856
+ const targets = targetNames ? TARGETS.filter((t2) => targetNames.includes(t2.flag)) : TARGETS.filter((t2) => t2.defaultEnabled);
2857
+ const agents = targets.map((t2) => t2.skillsAgent);
2858
+ if (hasNpx()) {
2859
+ const skipped = [];
2860
+ let count = 0;
2861
+ for (const source of SOURCES) {
2862
+ try {
2863
+ runSkillsAdd(source.repo, agents, true);
2864
+ count += 1;
2865
+ } catch {
2866
+ skipped.push(source.name);
2867
+ }
2868
+ }
2869
+ if (count > 0) {
2870
+ return { count, targets: targets.map((t2) => t2.name), skipped };
2871
+ }
2872
+ }
2873
+ if (!hasGit2()) {
2874
+ return { count: 0, targets: [], skipped: SOURCES.map((s) => s.name) };
2875
+ }
2876
+ const result = fallbackInstall(targets);
2877
+ return { count: result.count, targets: targets.map((t2) => t2.name), skipped: result.skipped };
2839
2878
  }
2840
2879
  function resolveTargets(args) {
2841
2880
  const hasAnyFlag = TARGETS.some((t2) => args[t2.flag] === true);
@@ -2846,70 +2885,57 @@ function resolveTargets(args) {
2846
2885
  }
2847
2886
  async function runInstall({ args }) {
2848
2887
  Wt2(c.bold("hyperframes skills"));
2849
- if (!hasGit2()) {
2850
- R2.error(c.error("git is required to install skills. Install git and retry."));
2851
- Gt(c.warn("No skills installed."));
2852
- return;
2853
- }
2854
2888
  const targets = resolveTargets(args);
2855
- const fetched = [];
2856
- for (const source of SOURCES) {
2857
- const spinner = be();
2858
- spinner.start(`Fetching ${source.name} skills...`);
2859
- try {
2860
- const skillsDir = fetchRepo(source);
2861
- if (existsSync3(skillsDir)) {
2862
- fetched.push({ source, skillsDir });
2863
- spinner.stop(c.success(`${source.name} skills fetched`));
2864
- } else {
2865
- spinner.stop(c.warn(`${source.name}: no skills directory found`));
2889
+ const agents = targets.map((t2) => t2.skillsAgent);
2890
+ if (hasNpx()) {
2891
+ const installed = [];
2892
+ const skippedSources = [];
2893
+ for (const source of SOURCES) {
2894
+ const spinner = be();
2895
+ spinner.start(`Installing ${source.name} skills...`);
2896
+ try {
2897
+ runSkillsAdd(source.repo, agents, true);
2898
+ installed.push(source.name);
2899
+ spinner.stop(c.success(`${source.name} skills installed`));
2900
+ } catch {
2901
+ skippedSources.push(source.name);
2902
+ spinner.stop(c.dim(`${source.name} skills skipped (unavailable)`));
2866
2903
  }
2867
- } catch {
2868
- spinner.stop(c.dim(`${source.name} skills skipped (repo not accessible)`));
2869
2904
  }
2870
- }
2871
- const allInstalled = [];
2872
- let counted = false;
2873
- for (const target of targets) {
2874
- const spinner = be();
2875
- spinner.start(`Installing to ${target.name}...`);
2876
- mkdirSync3(target.dir, { recursive: true });
2877
- let count = 0;
2878
- for (const { source, skillsDir } of fetched) {
2879
- const skills = installSkillsFromDir(skillsDir, target.dir, source.name);
2880
- count += skills.length;
2881
- if (!counted) allInstalled.push(...skills);
2905
+ console.log();
2906
+ console.log(` ${c.dim("Targets:")} ${targets.map((t2) => t2.name).join(", ")}`);
2907
+ if (skippedSources.length > 0) {
2908
+ console.log(` ${c.dim("Skipped:")} ${skippedSources.join(", ")}`);
2882
2909
  }
2883
- counted = true;
2884
- spinner.stop(c.success(`${count} skills \u2192 ${target.name} ${c.dim(target.dir)}`));
2910
+ console.log();
2911
+ if (installed.length > 0) {
2912
+ Gt(c.success(`${installed.join(" + ")} skills installed.`));
2913
+ return;
2914
+ }
2915
+ R2.warn("npx skills add failed \u2014 trying fallback...");
2916
+ }
2917
+ if (!hasGit2()) {
2918
+ R2.error(c.error("Neither npx nor git available. Install Node.js or git and retry."));
2919
+ Gt(c.warn("No skills installed."));
2920
+ return;
2885
2921
  }
2922
+ R2.info(c.dim("Using git fallback..."));
2923
+ const result = fallbackInstall(targets);
2886
2924
  console.log();
2887
2925
  for (const source of SOURCES) {
2888
- const names = allInstalled.filter((s) => s.source === source.name).map((s) => s.name);
2926
+ const names = result.installed.filter((s) => s.source === source.name).map((s) => s.name);
2889
2927
  if (names.length > 0) {
2890
2928
  const label2 = `${source.name}:`.padEnd(14);
2891
2929
  console.log(` ${c.dim(label2)} ${names.map((s) => c.accent(s)).join(", ")}`);
2892
2930
  }
2893
2931
  }
2894
2932
  console.log(` ${c.dim("Targets:")} ${targets.map((t2) => t2.name).join(", ")}`);
2895
- console.log();
2896
- const skippedSources = SOURCES.filter((s) => !fetched.some((f) => f.source.name === s.name));
2897
- if (skippedSources.length > 0) {
2898
- console.log(
2899
- ` ${c.dim("Skipped:")} ${skippedSources.map((s) => s.name).join(", ")} (repo not accessible)`
2900
- );
2933
+ if (result.skipped.length > 0) {
2934
+ console.log(` ${c.dim("Skipped:")} ${result.skipped.join(", ")}`);
2901
2935
  }
2902
2936
  console.log();
2903
- if (allInstalled.length > 0 && skippedSources.length > 0) {
2904
- const readySources = fetched.map((f) => f.source.name).join(", ");
2905
- const skippedNames = skippedSources.map((s) => s.name).join(", ");
2906
- Gt(
2907
- c.warn(
2908
- `${allInstalled.length} skills ready (${readySources}). Unavailable: ${skippedNames}.`
2909
- )
2910
- );
2911
- } else if (allInstalled.length > 0) {
2912
- Gt(c.success(`${allInstalled.length} skills ready.`));
2937
+ if (result.count > 0) {
2938
+ Gt(c.success(`${result.count} skills ready.`));
2913
2939
  } else {
2914
2940
  Gt(c.warn("No skills installed."));
2915
2941
  }
@@ -2925,24 +2951,28 @@ var init_install_skills = __esm({
2925
2951
  {
2926
2952
  name: "Claude Code",
2927
2953
  flag: "claude",
2954
+ skillsAgent: "claude-code",
2928
2955
  dir: join3(homedir3(), ".claude", "skills"),
2929
2956
  defaultEnabled: true
2930
2957
  },
2931
2958
  {
2932
2959
  name: "Gemini CLI",
2933
2960
  flag: "gemini",
2961
+ skillsAgent: "gemini-cli",
2934
2962
  dir: join3(homedir3(), ".gemini", "skills"),
2935
2963
  defaultEnabled: true
2936
2964
  },
2937
2965
  {
2938
2966
  name: "Codex CLI",
2939
2967
  flag: "codex",
2968
+ skillsAgent: "codex",
2940
2969
  dir: join3(homedir3(), ".codex", "skills"),
2941
2970
  defaultEnabled: true
2942
2971
  },
2943
2972
  {
2944
2973
  name: "Cursor",
2945
2974
  flag: "cursor",
2975
+ skillsAgent: "cursor",
2946
2976
  get dir() {
2947
2977
  return join3(process.cwd(), ".cursor", "skills");
2948
2978
  },
@@ -2952,13 +2982,13 @@ var init_install_skills = __esm({
2952
2982
  SOURCES = [
2953
2983
  {
2954
2984
  name: "HyperFrames",
2955
- repo: "https://github.com/heygen-com/hyperframes.git",
2985
+ repo: "heygen-com/hyperframes",
2956
2986
  skillsPath: "skills",
2957
2987
  cache: join3(homedir3(), ".cache", "hyperframes", "hyperframes-skills")
2958
2988
  },
2959
2989
  {
2960
2990
  name: "GSAP",
2961
- repo: "https://github.com/greensock/gsap-skills.git",
2991
+ repo: "greensock/gsap-skills",
2962
2992
  skillsPath: "skills",
2963
2993
  cache: join3(homedir3(), ".cache", "hyperframes", "gsap-skills")
2964
2994
  }
@@ -24261,12 +24291,21 @@ function transcodeToMp4(inputPath, outputPath) {
24261
24291
  child.on("error", () => resolvePromise(false));
24262
24292
  });
24263
24293
  }
24264
- function getStaticTemplateDir(templateId) {
24265
- const dir = dirname13(fileURLToPath5(import.meta.url));
24266
- const devPath = resolve14(dir, "..", "templates", templateId);
24267
- const builtPath = resolve14(dir, "templates", templateId);
24294
+ function resolveAssetDir(devSegments, builtSegments) {
24295
+ const base = dirname13(fileURLToPath5(import.meta.url));
24296
+ const devPath = resolve14(base, ...devSegments);
24297
+ const builtPath = resolve14(base, ...builtSegments);
24268
24298
  return existsSync26(devPath) ? devPath : builtPath;
24269
24299
  }
24300
+ function getStaticTemplateDir(templateId) {
24301
+ return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
24302
+ }
24303
+ function getSharedTemplateDir() {
24304
+ return resolveAssetDir(["..", "templates", "_shared"], ["templates", "_shared"]);
24305
+ }
24306
+ function getBundledSkillsDir() {
24307
+ return resolveAssetDir(["..", "..", "..", "..", "skills"], ["skills"]);
24308
+ }
24270
24309
  function patchVideoSrc(dir, videoFilename, durationSeconds) {
24271
24310
  const htmlFiles = readdirSync7(dir, { withFileTypes: true, recursive: true }).filter((e) => e.isFile() && e.name.endsWith(".html")).map((e) => join24(e.parentPath ?? e.path, e.name));
24272
24311
  for (const file of htmlFiles) {
@@ -24417,6 +24456,28 @@ function scaffoldProject(destDir, name, templateId, localVideoName, durationSeco
24417
24456
  ),
24418
24457
  "utf-8"
24419
24458
  );
24459
+ const sharedDir = getSharedTemplateDir();
24460
+ if (existsSync26(sharedDir)) {
24461
+ for (const entry of readdirSync7(sharedDir, { withFileTypes: true })) {
24462
+ const src = join24(sharedDir, entry.name);
24463
+ const dest = resolve14(destDir, entry.name);
24464
+ if (entry.isFile() || entry.isSymbolicLink()) {
24465
+ copyFileSync3(src, dest);
24466
+ }
24467
+ }
24468
+ }
24469
+ const skillsSrcDir = getBundledSkillsDir();
24470
+ if (existsSync26(skillsSrcDir)) {
24471
+ const projectSkills = ["compose-video", "captions"];
24472
+ for (const skill of projectSkills) {
24473
+ const src = join24(skillsSrcDir, skill);
24474
+ if (existsSync26(src)) {
24475
+ const dest = resolve14(destDir, ".claude", "skills", skill);
24476
+ mkdirSync18(dest, { recursive: true });
24477
+ cpSync2(src, dest, { recursive: true });
24478
+ }
24479
+ }
24480
+ }
24420
24481
  }
24421
24482
  async function nextStepLoop(destDir) {
24422
24483
  while (true) {
@@ -24571,9 +24632,28 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
24571
24632
  await installSkills(false);
24572
24633
  }
24573
24634
  console.log(c.success(`Created ${c.accent(name2 + "/")}`));
24574
- for (const f of readdirSync7(destDir2)) {
24635
+ for (const f of readdirSync7(destDir2).filter((f2) => !f2.startsWith("."))) {
24575
24636
  console.log(` ${c.accent(f)}`);
24576
24637
  }
24638
+ console.log();
24639
+ console.log("Next steps:");
24640
+ console.log(
24641
+ ` ${c.accent(`cd ${name2}`)} && ${c.accent("npx hyperframes dev")} ${c.dim("# preview in studio")}`
24642
+ );
24643
+ console.log(
24644
+ ` ${c.accent(`cd ${name2}`)} && ${c.accent("npx hyperframes render")} ${c.dim("# render to MP4")}`
24645
+ );
24646
+ console.log(
24647
+ ` ${c.accent("npx hyperframes docs")} ${c.dim("<topic>")} ${c.dim("# learn composition syntax")}`
24648
+ );
24649
+ console.log(
24650
+ ` ${c.dim("topics: data-attributes, gsap, compositions, rendering, templates, troubleshooting")}`
24651
+ );
24652
+ console.log();
24653
+ console.log(
24654
+ ` ${c.dim("AI skills installed \u2014 open this folder in your AI coding agent to get started.")}`
24655
+ );
24656
+ console.log(` ${c.dim("Full docs: hyperframes.heygen.com")}`);
24577
24657
  return;
24578
24658
  }
24579
24659
  Wt2("Create a new HyperFrames project");