hyperframes 0.1.8 → 0.1.10
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 +669 -289
- package/dist/skills/{captions → hyperframes-captions}/SKILL.md +1 -1
- package/dist/skills/{compose-video → hyperframes-compose}/SKILL.md +1 -1
- package/dist/templates/_shared/CLAUDE.md +21 -9
- package/dist/templates/play-mode/index.html +1 -1
- package/dist/templates/swiss-grid/compositions/graphics.html +1 -1
- package/dist/templates/swiss-grid/index.html +1 -1
- package/dist/templates/vignelli/index.html +1 -1
- package/dist/templates/warm-grain/index.html +1 -1
- package/package.json +2 -2
- /package/dist/skills/{compose-video → hyperframes-compose}/data-in-motion.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/house-style.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/bold-energetic.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/clean-corporate.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/dark-premium.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/jewel-rich.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/monochrome.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/nature-earth.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/neon-electric.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/pastel-soft.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/palettes/warm-editorial.md +0 -0
- /package/dist/skills/{compose-video → hyperframes-compose}/patterns.md +0 -0
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.
|
|
425
|
+
VERSION = true ? "0.1.10" : "0.0.0-dev";
|
|
426
426
|
}
|
|
427
427
|
});
|
|
428
428
|
|
|
@@ -599,6 +599,97 @@ var init_env = __esm({
|
|
|
599
599
|
}
|
|
600
600
|
});
|
|
601
601
|
|
|
602
|
+
// src/telemetry/system.ts
|
|
603
|
+
var system_exports = {};
|
|
604
|
+
__export(system_exports, {
|
|
605
|
+
bytesToMb: () => bytesToMb,
|
|
606
|
+
getFreeDiskMb: () => getFreeDiskMb,
|
|
607
|
+
getShmSizeMb: () => getShmSizeMb,
|
|
608
|
+
getSystemMeta: () => getSystemMeta
|
|
609
|
+
});
|
|
610
|
+
import { cpus, totalmem, platform, release } from "os";
|
|
611
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, statfsSync } from "fs";
|
|
612
|
+
function bytesToMb(bytes) {
|
|
613
|
+
return Math.trunc(bytes / (1024 * 1024));
|
|
614
|
+
}
|
|
615
|
+
function getSystemMeta() {
|
|
616
|
+
if (cached) return cached;
|
|
617
|
+
const cpuInfo = cpus();
|
|
618
|
+
const firstCpu = cpuInfo[0] ?? null;
|
|
619
|
+
cached = {
|
|
620
|
+
os_release: release(),
|
|
621
|
+
cpu_count: cpuInfo.length,
|
|
622
|
+
cpu_model: firstCpu?.model?.trim() ?? null,
|
|
623
|
+
cpu_speed: firstCpu?.speed ?? null,
|
|
624
|
+
memory_total_mb: bytesToMb(totalmem()),
|
|
625
|
+
is_docker: detectDocker(),
|
|
626
|
+
is_ci: detectCI(),
|
|
627
|
+
ci_name: getCIName(),
|
|
628
|
+
is_wsl: detectWSL(),
|
|
629
|
+
is_tty: Boolean(process.stdout?.isTTY)
|
|
630
|
+
};
|
|
631
|
+
return cached;
|
|
632
|
+
}
|
|
633
|
+
function detectDocker() {
|
|
634
|
+
try {
|
|
635
|
+
if (existsSync2("/.dockerenv")) return true;
|
|
636
|
+
if (platform() === "linux") {
|
|
637
|
+
const cgroup = readFileSync2("/proc/1/cgroup", "utf-8");
|
|
638
|
+
if (cgroup.includes("docker") || cgroup.includes("containerd")) return true;
|
|
639
|
+
}
|
|
640
|
+
} catch {
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
function detectCI() {
|
|
645
|
+
return process.env["CI"] === "true" || process.env["CI"] === "1" || process.env["CONTINUOUS_INTEGRATION"] === "true" || process.env["GITHUB_ACTIONS"] === "true" || process.env["GITLAB_CI"] === "true" || process.env["CIRCLECI"] === "true" || process.env["JENKINS_URL"] != null || process.env["BUILDKITE"] === "true" || process.env["TRAVIS"] === "true" || false;
|
|
646
|
+
}
|
|
647
|
+
function getCIName() {
|
|
648
|
+
if (process.env["GITHUB_ACTIONS"] === "true") return "github_actions";
|
|
649
|
+
if (process.env["GITLAB_CI"] === "true") return "gitlab_ci";
|
|
650
|
+
if (process.env["CIRCLECI"] === "true") return "circleci";
|
|
651
|
+
if (process.env["JENKINS_URL"] != null) return "jenkins";
|
|
652
|
+
if (process.env["BUILDKITE"] === "true") return "buildkite";
|
|
653
|
+
if (process.env["TRAVIS"] === "true") return "travis";
|
|
654
|
+
if (detectCI()) return "unknown";
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
function detectWSL() {
|
|
658
|
+
if (platform() !== "linux") return false;
|
|
659
|
+
try {
|
|
660
|
+
const osRelease = release().toLowerCase();
|
|
661
|
+
if (osRelease.includes("microsoft") || osRelease.includes("wsl")) return true;
|
|
662
|
+
const procVersion = readFileSync2("/proc/version", "utf-8").toLowerCase();
|
|
663
|
+
return procVersion.includes("microsoft") || procVersion.includes("wsl");
|
|
664
|
+
} catch {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function getShmSizeMb() {
|
|
669
|
+
if (platform() !== "linux") return null;
|
|
670
|
+
try {
|
|
671
|
+
const stats = statfsSync("/dev/shm");
|
|
672
|
+
return bytesToMb(stats.bsize * stats.blocks);
|
|
673
|
+
} catch {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function getFreeDiskMb(path = ".") {
|
|
678
|
+
try {
|
|
679
|
+
const stats = statfsSync(path);
|
|
680
|
+
return bytesToMb(stats.bsize * stats.bavail);
|
|
681
|
+
} catch {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
var cached;
|
|
686
|
+
var init_system = __esm({
|
|
687
|
+
"src/telemetry/system.ts"() {
|
|
688
|
+
"use strict";
|
|
689
|
+
cached = null;
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
602
693
|
// src/telemetry/client.ts
|
|
603
694
|
function shouldTrack() {
|
|
604
695
|
if (telemetryEnabled !== null) return telemetryEnabled;
|
|
@@ -624,6 +715,7 @@ function shouldTrack() {
|
|
|
624
715
|
}
|
|
625
716
|
function trackEvent(event, properties = {}) {
|
|
626
717
|
if (!shouldTrack()) return;
|
|
718
|
+
const sys = getSystemMeta();
|
|
627
719
|
eventQueue.push({
|
|
628
720
|
event,
|
|
629
721
|
properties: {
|
|
@@ -631,7 +723,17 @@ function trackEvent(event, properties = {}) {
|
|
|
631
723
|
cli_version: VERSION,
|
|
632
724
|
os: process.platform,
|
|
633
725
|
arch: process.arch,
|
|
634
|
-
node_version: process.version
|
|
726
|
+
node_version: process.version,
|
|
727
|
+
os_release: sys.os_release,
|
|
728
|
+
cpu_count: sys.cpu_count,
|
|
729
|
+
cpu_model: sys.cpu_model ?? void 0,
|
|
730
|
+
cpu_speed: sys.cpu_speed ?? void 0,
|
|
731
|
+
memory_total_mb: sys.memory_total_mb,
|
|
732
|
+
is_docker: sys.is_docker,
|
|
733
|
+
is_ci: sys.is_ci,
|
|
734
|
+
ci_name: sys.ci_name ?? void 0,
|
|
735
|
+
is_wsl: sys.is_wsl,
|
|
736
|
+
is_tty: sys.is_tty
|
|
635
737
|
},
|
|
636
738
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
637
739
|
});
|
|
@@ -655,7 +757,7 @@ async function flush() {
|
|
|
655
757
|
try {
|
|
656
758
|
await fetch(`${POSTHOG_HOST}/batch/`, {
|
|
657
759
|
method: "POST",
|
|
658
|
-
headers: { "Content-Type": "application/json" },
|
|
760
|
+
headers: { "Content-Type": "application/json", Connection: "close" },
|
|
659
761
|
body: JSON.stringify({ api_key: POSTHOG_API_KEY, batch }),
|
|
660
762
|
signal: controller.signal
|
|
661
763
|
});
|
|
@@ -713,6 +815,7 @@ var init_client = __esm({
|
|
|
713
815
|
init_version();
|
|
714
816
|
init_colors();
|
|
715
817
|
init_env();
|
|
818
|
+
init_system();
|
|
716
819
|
POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
|
|
717
820
|
POSTHOG_HOST = "https://us.i.posthog.com";
|
|
718
821
|
FLUSH_TIMEOUT_MS = 5e3;
|
|
@@ -722,6 +825,14 @@ var init_client = __esm({
|
|
|
722
825
|
});
|
|
723
826
|
|
|
724
827
|
// src/telemetry/events.ts
|
|
828
|
+
var events_exports = {};
|
|
829
|
+
__export(events_exports, {
|
|
830
|
+
trackBrowserInstall: () => trackBrowserInstall,
|
|
831
|
+
trackCommand: () => trackCommand,
|
|
832
|
+
trackInitTemplate: () => trackInitTemplate,
|
|
833
|
+
trackRenderComplete: () => trackRenderComplete,
|
|
834
|
+
trackRenderError: () => trackRenderError
|
|
835
|
+
});
|
|
725
836
|
function trackCommand(command2) {
|
|
726
837
|
trackEvent("cli_command", { command: command2 });
|
|
727
838
|
}
|
|
@@ -732,14 +843,30 @@ function trackRenderComplete(props) {
|
|
|
732
843
|
quality: props.quality,
|
|
733
844
|
workers: props.workers,
|
|
734
845
|
docker: props.docker,
|
|
735
|
-
gpu: props.gpu
|
|
846
|
+
gpu: props.gpu,
|
|
847
|
+
composition_duration_ms: props.compositionDurationMs,
|
|
848
|
+
composition_width: props.compositionWidth,
|
|
849
|
+
composition_height: props.compositionHeight,
|
|
850
|
+
total_frames: props.totalFrames,
|
|
851
|
+
speed_ratio: props.speedRatio,
|
|
852
|
+
capture_avg_ms: props.captureAvgMs,
|
|
853
|
+
capture_peak_ms: props.capturePeakMs,
|
|
854
|
+
peak_memory_mb: props.peakMemoryMb,
|
|
855
|
+
memory_free_mb: props.memoryFreeMb
|
|
736
856
|
});
|
|
737
857
|
}
|
|
738
858
|
function trackRenderError(props) {
|
|
739
859
|
trackEvent("render_error", {
|
|
740
860
|
fps: props.fps,
|
|
741
861
|
quality: props.quality,
|
|
742
|
-
docker: props.docker
|
|
862
|
+
docker: props.docker,
|
|
863
|
+
workers: props.workers,
|
|
864
|
+
gpu: props.gpu,
|
|
865
|
+
failed_stage: props.failedStage,
|
|
866
|
+
error_message: props.errorMessage,
|
|
867
|
+
elapsed_ms: props.elapsedMs,
|
|
868
|
+
peak_memory_mb: props.peakMemoryMb,
|
|
869
|
+
memory_free_mb: props.memoryFreeMb
|
|
743
870
|
});
|
|
744
871
|
}
|
|
745
872
|
function trackInitTemplate(templateId) {
|
|
@@ -772,7 +899,10 @@ async function checkForUpdate(force) {
|
|
|
772
899
|
try {
|
|
773
900
|
const controller = new AbortController();
|
|
774
901
|
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
775
|
-
const res = await fetch(NPM_REGISTRY_URL, {
|
|
902
|
+
const res = await fetch(NPM_REGISTRY_URL, {
|
|
903
|
+
signal: controller.signal,
|
|
904
|
+
headers: { Connection: "close" }
|
|
905
|
+
});
|
|
776
906
|
clearTimeout(timeout);
|
|
777
907
|
if (!res.ok) return fallbackResult(config.latestVersion);
|
|
778
908
|
const data = await res.json();
|
|
@@ -2536,7 +2666,15 @@ var init_generators = __esm({
|
|
|
2536
2666
|
{ id: "warm-grain", label: "Warm Grain", hint: "Cream aesthetic with grain texture" },
|
|
2537
2667
|
{ id: "play-mode", label: "Play Mode", hint: "Playful elastic animations" },
|
|
2538
2668
|
{ id: "swiss-grid", label: "Swiss Grid", hint: "Structured grid layout" },
|
|
2539
|
-
{ id: "vignelli", label: "Vignelli", hint: "Bold typography with red accents" }
|
|
2669
|
+
{ id: "vignelli", label: "Vignelli", hint: "Bold typography with red accents" },
|
|
2670
|
+
{ id: "decision-tree", label: "Decision Tree", hint: "Animated flowchart with branching paths" },
|
|
2671
|
+
{ id: "kinetic-type", label: "Kinetic Type", hint: "Bold kinetic typography promo" },
|
|
2672
|
+
{
|
|
2673
|
+
id: "product-promo",
|
|
2674
|
+
label: "Product Promo",
|
|
2675
|
+
hint: "Multi-scene product showcase with SVG assets"
|
|
2676
|
+
},
|
|
2677
|
+
{ id: "nyt-graph", label: "NYT Graph", hint: "Animated data chart in print editorial style" }
|
|
2540
2678
|
];
|
|
2541
2679
|
}
|
|
2542
2680
|
});
|
|
@@ -2553,8 +2691,8 @@ __export(manager_exports, {
|
|
|
2553
2691
|
hasFFmpeg: () => hasFFmpeg
|
|
2554
2692
|
});
|
|
2555
2693
|
import { execFileSync } from "child_process";
|
|
2556
|
-
import { existsSync as
|
|
2557
|
-
import { homedir as homedir2, platform } from "os";
|
|
2694
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, createWriteStream, rmSync } from "fs";
|
|
2695
|
+
import { homedir as homedir2, platform as platform2 } from "os";
|
|
2558
2696
|
import { join as join2 } from "path";
|
|
2559
2697
|
import { get as httpsGet } from "https";
|
|
2560
2698
|
import { pipeline } from "stream/promises";
|
|
@@ -2597,7 +2735,7 @@ function whichBinary(name) {
|
|
|
2597
2735
|
}
|
|
2598
2736
|
function findFromEnv() {
|
|
2599
2737
|
const envPath = process.env["HYPERFRAMES_WHISPER_PATH"];
|
|
2600
|
-
if (envPath &&
|
|
2738
|
+
if (envPath && existsSync3(envPath)) {
|
|
2601
2739
|
return { executablePath: envPath, source: "env" };
|
|
2602
2740
|
}
|
|
2603
2741
|
return void 0;
|
|
@@ -2607,9 +2745,9 @@ function findFromSystem() {
|
|
|
2607
2745
|
const path = whichBinary(name);
|
|
2608
2746
|
if (path) return { executablePath: path, source: "system" };
|
|
2609
2747
|
}
|
|
2610
|
-
if (
|
|
2748
|
+
if (platform2() === "darwin") {
|
|
2611
2749
|
for (const p of ["/opt/homebrew/bin/whisper-cli", "/usr/local/bin/whisper-cli"]) {
|
|
2612
|
-
if (
|
|
2750
|
+
if (existsSync3(p)) return { executablePath: p, source: "system" };
|
|
2613
2751
|
}
|
|
2614
2752
|
}
|
|
2615
2753
|
return void 0;
|
|
@@ -2619,15 +2757,15 @@ function findBuiltBinary() {
|
|
|
2619
2757
|
join2(BUILD_DIR, "build", "bin", "whisper-cli"),
|
|
2620
2758
|
join2(BUILD_DIR, "build", "whisper-cli")
|
|
2621
2759
|
]) {
|
|
2622
|
-
if (
|
|
2760
|
+
if (existsSync3(p)) return { executablePath: p, source: "build" };
|
|
2623
2761
|
}
|
|
2624
2762
|
return void 0;
|
|
2625
2763
|
}
|
|
2626
2764
|
function buildFromSource(onProgress) {
|
|
2627
|
-
if (
|
|
2765
|
+
if (existsSync3(BUILD_DIR) && !findBuiltBinary()) {
|
|
2628
2766
|
rmSync(BUILD_DIR, { recursive: true, force: true });
|
|
2629
2767
|
}
|
|
2630
|
-
if (!
|
|
2768
|
+
if (!existsSync3(BUILD_DIR)) {
|
|
2631
2769
|
onProgress?.("Downloading whisper.cpp...");
|
|
2632
2770
|
mkdirSync2(join2(homedir2(), ".cache", "hyperframes", "whisper"), {
|
|
2633
2771
|
recursive: true
|
|
@@ -2670,7 +2808,7 @@ function findWhisper() {
|
|
|
2670
2808
|
return findFromEnv() ?? findFromSystem() ?? findBuiltBinary();
|
|
2671
2809
|
}
|
|
2672
2810
|
function getInstallInstructions() {
|
|
2673
|
-
if (
|
|
2811
|
+
if (platform2() === "darwin") {
|
|
2674
2812
|
return "brew install whisper-cpp";
|
|
2675
2813
|
}
|
|
2676
2814
|
return "See https://github.com/ggml-org/whisper.cpp#building";
|
|
@@ -2687,7 +2825,7 @@ function hasCmake() {
|
|
|
2687
2825
|
async function ensureWhisper(options) {
|
|
2688
2826
|
const existing = findWhisper();
|
|
2689
2827
|
if (existing) return existing;
|
|
2690
|
-
if (
|
|
2828
|
+
if (platform2() === "darwin" && hasBrew()) {
|
|
2691
2829
|
options?.onProgress?.("Installing whisper-cpp via Homebrew...");
|
|
2692
2830
|
try {
|
|
2693
2831
|
execFileSync("brew", ["install", "whisper-cpp"], {
|
|
@@ -2709,11 +2847,11 @@ async function ensureWhisper(options) {
|
|
|
2709
2847
|
}
|
|
2710
2848
|
async function ensureModel(model = DEFAULT_MODEL, options) {
|
|
2711
2849
|
const modelPath = join2(MODELS_DIR, `ggml-${model}.bin`);
|
|
2712
|
-
if (
|
|
2850
|
+
if (existsSync3(modelPath)) return modelPath;
|
|
2713
2851
|
mkdirSync2(MODELS_DIR, { recursive: true });
|
|
2714
2852
|
options?.onProgress?.(`Downloading model ${model}...`);
|
|
2715
2853
|
await downloadFile(getModelUrl(model), modelPath);
|
|
2716
|
-
if (!
|
|
2854
|
+
if (!existsSync3(modelPath)) {
|
|
2717
2855
|
throw new Error(`Model download failed: ${model}`);
|
|
2718
2856
|
}
|
|
2719
2857
|
return modelPath;
|
|
@@ -2744,7 +2882,7 @@ __export(install_skills_exports, {
|
|
|
2744
2882
|
default: () => install_skills_default,
|
|
2745
2883
|
installAllSkills: () => installAllSkills
|
|
2746
2884
|
});
|
|
2747
|
-
import { existsSync as
|
|
2885
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, rmSync as rmSync2, cpSync } from "fs";
|
|
2748
2886
|
import { join as join3, dirname } from "path";
|
|
2749
2887
|
import { homedir as homedir3 } from "os";
|
|
2750
2888
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -2784,7 +2922,7 @@ function gitClone(repo, dest) {
|
|
|
2784
2922
|
}
|
|
2785
2923
|
function fetchRepo(source) {
|
|
2786
2924
|
const gitUrl = `https://github.com/${source.repo}.git`;
|
|
2787
|
-
if (
|
|
2925
|
+
if (existsSync4(source.cache)) {
|
|
2788
2926
|
try {
|
|
2789
2927
|
execFileSync2("git", ["pull", "--ff-only"], {
|
|
2790
2928
|
cwd: source.cache,
|
|
@@ -2794,7 +2932,7 @@ function fetchRepo(source) {
|
|
|
2794
2932
|
});
|
|
2795
2933
|
} catch {
|
|
2796
2934
|
const skillsDir2 = join3(source.cache, source.skillsPath);
|
|
2797
|
-
if (
|
|
2935
|
+
if (existsSync4(skillsDir2)) return skillsDir2;
|
|
2798
2936
|
rmSync2(source.cache, { recursive: true, force: true });
|
|
2799
2937
|
gitClone(gitUrl, source.cache);
|
|
2800
2938
|
}
|
|
@@ -2803,18 +2941,18 @@ function fetchRepo(source) {
|
|
|
2803
2941
|
gitClone(gitUrl, source.cache);
|
|
2804
2942
|
}
|
|
2805
2943
|
const skillsDir = join3(source.cache, source.skillsPath);
|
|
2806
|
-
return
|
|
2944
|
+
return existsSync4(skillsDir) ? skillsDir : void 0;
|
|
2807
2945
|
}
|
|
2808
2946
|
function installSkillsFromDir(sourceDir, targetDir, sourceName) {
|
|
2809
2947
|
const installed = [];
|
|
2810
|
-
if (!
|
|
2948
|
+
if (!existsSync4(sourceDir)) return installed;
|
|
2811
2949
|
const entries2 = readdirSync(sourceDir, { withFileTypes: true });
|
|
2812
2950
|
for (const entry of entries2) {
|
|
2813
2951
|
if (!entry.isDirectory()) continue;
|
|
2814
2952
|
const skillFile = join3(sourceDir, entry.name, "SKILL.md");
|
|
2815
|
-
if (!
|
|
2953
|
+
if (!existsSync4(skillFile)) continue;
|
|
2816
2954
|
const destDir = join3(targetDir, entry.name);
|
|
2817
|
-
if (
|
|
2955
|
+
if (existsSync4(destDir)) rmSync2(destDir, { recursive: true, force: true });
|
|
2818
2956
|
mkdirSync3(destDir, { recursive: true });
|
|
2819
2957
|
cpSync(join3(sourceDir, entry.name), destDir, { recursive: true });
|
|
2820
2958
|
installed.push({ name: entry.name, source: sourceName });
|
|
@@ -3844,6 +3982,76 @@ ${right.raw}`)
|
|
|
3844
3982
|
});
|
|
3845
3983
|
}
|
|
3846
3984
|
}
|
|
3985
|
+
for (const script of scripts) {
|
|
3986
|
+
const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
|
|
3987
|
+
let tlMatch;
|
|
3988
|
+
while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
|
|
3989
|
+
pushFinding({
|
|
3990
|
+
code: "template_literal_selector",
|
|
3991
|
+
severity: "error",
|
|
3992
|
+
message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
|
|
3993
|
+
file: filePath,
|
|
3994
|
+
fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
|
|
3995
|
+
snippet: truncateSnippet(tlMatch[0])
|
|
3996
|
+
});
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
{
|
|
4000
|
+
const cssTranslateSelectors = /* @__PURE__ */ new Map();
|
|
4001
|
+
const cssScaleSelectors = /* @__PURE__ */ new Map();
|
|
4002
|
+
for (const style of styles) {
|
|
4003
|
+
for (const [, selector, body] of style.content.matchAll(
|
|
4004
|
+
/([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
|
|
4005
|
+
)) {
|
|
4006
|
+
const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
|
|
4007
|
+
if (!tMatch || !tMatch[1]) continue;
|
|
4008
|
+
const transformVal = tMatch[1].trim();
|
|
4009
|
+
if (/translate/i.test(transformVal)) {
|
|
4010
|
+
cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
|
|
4011
|
+
}
|
|
4012
|
+
if (/scale/i.test(transformVal)) {
|
|
4013
|
+
cssScaleSelectors.set((selector ?? "").trim(), transformVal);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
if (cssTranslateSelectors.size > 0 || cssScaleSelectors.size > 0) {
|
|
4018
|
+
for (const script of scripts) {
|
|
4019
|
+
if (!/gsap\.timeline/.test(script.content)) continue;
|
|
4020
|
+
const windows = extractGsapWindows(script.content);
|
|
4021
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
4022
|
+
for (const win of windows) {
|
|
4023
|
+
if (win.method === "fromTo") continue;
|
|
4024
|
+
const sel = win.targetSelector;
|
|
4025
|
+
const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
|
|
4026
|
+
const translateProps = win.properties.filter(
|
|
4027
|
+
(p) => ["x", "y", "xPercent", "yPercent"].includes(p)
|
|
4028
|
+
);
|
|
4029
|
+
const scaleProps = win.properties.filter((p) => p === "scale");
|
|
4030
|
+
const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
|
|
4031
|
+
const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
|
|
4032
|
+
if (!cssFromTranslate && !cssFromScale) continue;
|
|
4033
|
+
const existing = conflicts.get(sel) ?? {
|
|
4034
|
+
cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
|
|
4035
|
+
props: /* @__PURE__ */ new Set(),
|
|
4036
|
+
raw: win.raw
|
|
4037
|
+
};
|
|
4038
|
+
for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
|
|
4039
|
+
conflicts.set(sel, existing);
|
|
4040
|
+
}
|
|
4041
|
+
for (const [sel, { cssTransform, props, raw }] of conflicts) {
|
|
4042
|
+
const propList = [...props].join("/");
|
|
4043
|
+
pushFinding({
|
|
4044
|
+
code: "gsap_css_transform_conflict",
|
|
4045
|
+
severity: "warning",
|
|
4046
|
+
message: `"${sel}" has CSS \`transform: ${cssTransform}\` and a GSAP tween animates ${propList}. GSAP will overwrite the full CSS transform, discarding any translateX(-50%) centering or CSS scale value.`,
|
|
4047
|
+
selector: sel,
|
|
4048
|
+
fixHint: `Remove the transform from CSS and use tl.fromTo('${sel}', { xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns the full transform state. tl.fromTo is exempt from this rule.`,
|
|
4049
|
+
snippet: truncateSnippet(raw)
|
|
4050
|
+
});
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
}
|
|
3847
4055
|
const errorCount = findings.filter((finding) => finding.severity === "error").length;
|
|
3848
4056
|
const warningCount = findings.length - errorCount;
|
|
3849
4057
|
return {
|
|
@@ -3987,6 +4195,7 @@ function extractGsapWindows(script) {
|
|
|
3987
4195
|
end: animation.position + meta.effectiveDuration,
|
|
3988
4196
|
properties: meta.properties.length > 0 ? meta.properties : Object.keys(animation.properties),
|
|
3989
4197
|
overwriteAuto: meta.overwriteAuto,
|
|
4198
|
+
method: match[1] ?? "to",
|
|
3990
4199
|
raw
|
|
3991
4200
|
});
|
|
3992
4201
|
}
|
|
@@ -4172,7 +4381,7 @@ var init_staticGuard = __esm({
|
|
|
4172
4381
|
});
|
|
4173
4382
|
|
|
4174
4383
|
// ../core/src/compiler/htmlBundler.ts
|
|
4175
|
-
import { readFileSync as
|
|
4384
|
+
import { readFileSync as readFileSync3, existsSync as existsSync5 } from "fs";
|
|
4176
4385
|
import { join as join4, resolve as resolve2, isAbsolute, sep } from "path";
|
|
4177
4386
|
import * as cheerio from "cheerio";
|
|
4178
4387
|
import { transformSync } from "esbuild";
|
|
@@ -4235,17 +4444,17 @@ function isRelativeUrl(url) {
|
|
|
4235
4444
|
return !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("//") && !url.startsWith("data:") && !isAbsolute(url);
|
|
4236
4445
|
}
|
|
4237
4446
|
function safeReadFile(filePath) {
|
|
4238
|
-
if (!
|
|
4447
|
+
if (!existsSync5(filePath)) return null;
|
|
4239
4448
|
try {
|
|
4240
|
-
return
|
|
4449
|
+
return readFileSync3(filePath, "utf-8");
|
|
4241
4450
|
} catch {
|
|
4242
4451
|
return null;
|
|
4243
4452
|
}
|
|
4244
4453
|
}
|
|
4245
4454
|
function safeReadFileBuffer(filePath) {
|
|
4246
|
-
if (!
|
|
4455
|
+
if (!existsSync5(filePath)) return null;
|
|
4247
4456
|
try {
|
|
4248
|
-
return
|
|
4457
|
+
return readFileSync3(filePath);
|
|
4249
4458
|
} catch {
|
|
4250
4459
|
return null;
|
|
4251
4460
|
}
|
|
@@ -4433,8 +4642,8 @@ function stripJsCommentsParserSafe(source) {
|
|
|
4433
4642
|
}
|
|
4434
4643
|
async function bundleToSingleHtml(projectDir, options) {
|
|
4435
4644
|
const indexPath = join4(projectDir, "index.html");
|
|
4436
|
-
if (!
|
|
4437
|
-
const rawHtml =
|
|
4645
|
+
if (!existsSync5(indexPath)) throw new Error("index.html not found in project directory");
|
|
4646
|
+
const rawHtml = readFileSync3(indexPath, "utf-8");
|
|
4438
4647
|
const compiled = await compileHtml(rawHtml, projectDir, options?.probeMediaDuration);
|
|
4439
4648
|
const staticGuard = validateHyperframeHtmlContract(compiled);
|
|
4440
4649
|
if (!staticGuard.isValid) {
|
|
@@ -17298,7 +17507,7 @@ var init_config2 = __esm({
|
|
|
17298
17507
|
});
|
|
17299
17508
|
|
|
17300
17509
|
// ../engine/src/services/browserManager.ts
|
|
17301
|
-
import { existsSync as
|
|
17510
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2 } from "fs";
|
|
17302
17511
|
import { join as join5 } from "path";
|
|
17303
17512
|
import { homedir as homedir4 } from "os";
|
|
17304
17513
|
async function getPuppeteer() {
|
|
@@ -17321,7 +17530,7 @@ function resolveHeadlessShellPath(config) {
|
|
|
17321
17530
|
return process.env.PRODUCER_HEADLESS_SHELL_PATH;
|
|
17322
17531
|
}
|
|
17323
17532
|
const baseDir = join5(homedir4(), ".cache", "puppeteer", "chrome-headless-shell");
|
|
17324
|
-
if (!
|
|
17533
|
+
if (!existsSync6(baseDir)) return void 0;
|
|
17325
17534
|
try {
|
|
17326
17535
|
const versions = readdirSync2(baseDir).sort().reverse();
|
|
17327
17536
|
for (const version of versions) {
|
|
@@ -17332,7 +17541,7 @@ function resolveHeadlessShellPath(config) {
|
|
|
17332
17541
|
join5(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
|
|
17333
17542
|
];
|
|
17334
17543
|
for (const binary of candidates) {
|
|
17335
|
-
if (
|
|
17544
|
+
if (existsSync6(binary)) return binary;
|
|
17336
17545
|
}
|
|
17337
17546
|
}
|
|
17338
17547
|
} catch {
|
|
@@ -18025,9 +18234,9 @@ async function beginFrameCapture(page, options, frameTimeTicks, interval) {
|
|
|
18025
18234
|
buffer = Buffer.from(result.screenshotData, "base64");
|
|
18026
18235
|
lastFrameCache.set(page, buffer);
|
|
18027
18236
|
} else {
|
|
18028
|
-
const
|
|
18029
|
-
if (
|
|
18030
|
-
buffer =
|
|
18237
|
+
const cached2 = lastFrameCache.get(page);
|
|
18238
|
+
if (cached2) {
|
|
18239
|
+
buffer = cached2;
|
|
18031
18240
|
} else {
|
|
18032
18241
|
const retry = await client.send("HeadlessExperimental.beginFrame", {
|
|
18033
18242
|
frameTimeTicks: frameTimeTicks + 1e-3,
|
|
@@ -18163,10 +18372,10 @@ var init_screenshotService = __esm({
|
|
|
18163
18372
|
});
|
|
18164
18373
|
|
|
18165
18374
|
// ../engine/src/services/frameCapture.ts
|
|
18166
|
-
import { existsSync as
|
|
18375
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
18167
18376
|
import { join as join6 } from "path";
|
|
18168
18377
|
async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
|
|
18169
|
-
if (!
|
|
18378
|
+
if (!existsSync7(outputDir)) mkdirSync4(outputDir, { recursive: true });
|
|
18170
18379
|
const headlessShell = resolveHeadlessShellPath(config);
|
|
18171
18380
|
const isLinux = process.platform === "linux";
|
|
18172
18381
|
const forceScreenshot = config?.forceScreenshot ?? DEFAULT_CONFIG2.forceScreenshot;
|
|
@@ -18326,7 +18535,7 @@ async function initializeSession(session) {
|
|
|
18326
18535
|
async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
|
|
18327
18536
|
try {
|
|
18328
18537
|
const diagnosticsDir = join6(session.outputDir, "diagnostics");
|
|
18329
|
-
if (!
|
|
18538
|
+
if (!existsSync7(diagnosticsDir)) mkdirSync4(diagnosticsDir, { recursive: true });
|
|
18330
18539
|
const base = join6(diagnosticsDir, `frame-error-${frameIndex}`);
|
|
18331
18540
|
await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
|
|
18332
18541
|
const html = await session.page.content();
|
|
@@ -18440,7 +18649,7 @@ async function closeCaptureSession(session) {
|
|
|
18440
18649
|
session.isInitialized = false;
|
|
18441
18650
|
}
|
|
18442
18651
|
function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
|
|
18443
|
-
if (!
|
|
18652
|
+
if (!existsSync7(outputDir)) {
|
|
18444
18653
|
mkdirSync4(outputDir, { recursive: true });
|
|
18445
18654
|
}
|
|
18446
18655
|
session.outputDir = outputDir;
|
|
@@ -18595,7 +18804,7 @@ var init_runFfmpeg = __esm({
|
|
|
18595
18804
|
|
|
18596
18805
|
// ../engine/src/services/chunkEncoder.ts
|
|
18597
18806
|
import { spawn as spawn3 } from "child_process";
|
|
18598
|
-
import { copyFileSync, existsSync as
|
|
18807
|
+
import { copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
18599
18808
|
import { join as join7, dirname as dirname3 } from "path";
|
|
18600
18809
|
function getEncoderPreset(quality, format = "mp4") {
|
|
18601
18810
|
const base = ENCODER_PRESETS[quality];
|
|
@@ -18678,7 +18887,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
18678
18887
|
async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config) {
|
|
18679
18888
|
const startTime = Date.now();
|
|
18680
18889
|
const outputDir = dirname3(outputPath);
|
|
18681
|
-
if (!
|
|
18890
|
+
if (!existsSync8(outputDir)) mkdirSync5(outputDir, { recursive: true });
|
|
18682
18891
|
const files = readdirSync3(framesDir).filter((f) => f.match(/\.(jpg|jpeg|png)$/i));
|
|
18683
18892
|
const frameCount = files.length;
|
|
18684
18893
|
if (frameCount === 0) {
|
|
@@ -18744,7 +18953,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
18744
18953
|
});
|
|
18745
18954
|
return;
|
|
18746
18955
|
}
|
|
18747
|
-
const fileSize =
|
|
18956
|
+
const fileSize = existsSync8(outputPath) ? statSync(outputPath).size : 0;
|
|
18748
18957
|
resolve17({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
|
|
18749
18958
|
});
|
|
18750
18959
|
ffmpeg.on("error", (err) => {
|
|
@@ -18777,7 +18986,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
18777
18986
|
const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
|
|
18778
18987
|
const chunkCount = Math.ceil(files.length / chunkSize);
|
|
18779
18988
|
const chunkDir = join7(dirname3(outputPath), "chunk-encode");
|
|
18780
|
-
if (!
|
|
18989
|
+
if (!existsSync8(chunkDir)) mkdirSync5(chunkDir, { recursive: true });
|
|
18781
18990
|
const chunkPaths = [];
|
|
18782
18991
|
for (let i = 0; i < chunkCount; i++) {
|
|
18783
18992
|
if (signal?.aborted) {
|
|
@@ -18873,7 +19082,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
18873
19082
|
error: concatResult.error
|
|
18874
19083
|
};
|
|
18875
19084
|
}
|
|
18876
|
-
const fileSize =
|
|
19085
|
+
const fileSize = existsSync8(outputPath) ? statSync(outputPath).size : 0;
|
|
18877
19086
|
return {
|
|
18878
19087
|
success: true,
|
|
18879
19088
|
outputPath,
|
|
@@ -18884,7 +19093,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
18884
19093
|
}
|
|
18885
19094
|
async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config) {
|
|
18886
19095
|
const outputDir = dirname3(outputPath);
|
|
18887
|
-
if (!
|
|
19096
|
+
if (!existsSync8(outputDir)) mkdirSync5(outputDir, { recursive: true });
|
|
18888
19097
|
const isWebm = outputPath.endsWith(".webm");
|
|
18889
19098
|
const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
|
|
18890
19099
|
if (isWebm) {
|
|
@@ -18951,7 +19160,7 @@ var init_chunkEncoder = __esm({
|
|
|
18951
19160
|
|
|
18952
19161
|
// ../engine/src/services/streamingEncoder.ts
|
|
18953
19162
|
import { spawn as spawn4 } from "child_process";
|
|
18954
|
-
import { existsSync as
|
|
19163
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, statSync as statSync2 } from "fs";
|
|
18955
19164
|
import { dirname as dirname4 } from "path";
|
|
18956
19165
|
function createFrameReorderBuffer(startFrame, endFrame) {
|
|
18957
19166
|
let nextFrame = startFrame;
|
|
@@ -19060,7 +19269,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
19060
19269
|
}
|
|
19061
19270
|
async function spawnStreamingEncoder(outputPath, options, signal, config) {
|
|
19062
19271
|
const outputDir = dirname4(outputPath);
|
|
19063
|
-
if (!
|
|
19272
|
+
if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
|
|
19064
19273
|
let gpuEncoder = null;
|
|
19065
19274
|
if (options.useGpu) {
|
|
19066
19275
|
gpuEncoder = await getCachedGpuEncoder();
|
|
@@ -19140,7 +19349,7 @@ Process error: ${err.message}`;
|
|
|
19140
19349
|
error: `FFmpeg exited with code ${exitCode}`
|
|
19141
19350
|
};
|
|
19142
19351
|
}
|
|
19143
|
-
const fileSize =
|
|
19352
|
+
const fileSize = existsSync9(outputPath) ? statSync2(outputPath).size : 0;
|
|
19144
19353
|
return { success: true, durationMs, fileSize };
|
|
19145
19354
|
},
|
|
19146
19355
|
getExitStatus: () => exitStatus
|
|
@@ -19168,9 +19377,9 @@ function parseFrameRate(frameRateStr) {
|
|
|
19168
19377
|
return parseFloat(frameRateStr) || 0;
|
|
19169
19378
|
}
|
|
19170
19379
|
async function extractVideoMetadata(filePath) {
|
|
19171
|
-
const
|
|
19172
|
-
if (
|
|
19173
|
-
return
|
|
19380
|
+
const cached2 = videoMetadataCache.get(filePath);
|
|
19381
|
+
if (cached2) {
|
|
19382
|
+
return cached2;
|
|
19174
19383
|
}
|
|
19175
19384
|
const probePromise = new Promise((resolve17, reject) => {
|
|
19176
19385
|
const args = [
|
|
@@ -19240,9 +19449,9 @@ async function extractVideoMetadata(filePath) {
|
|
|
19240
19449
|
return probePromise;
|
|
19241
19450
|
}
|
|
19242
19451
|
async function extractAudioMetadata(filePath) {
|
|
19243
|
-
const
|
|
19244
|
-
if (
|
|
19245
|
-
return
|
|
19452
|
+
const cached2 = audioMetadataCache.get(filePath);
|
|
19453
|
+
if (cached2) {
|
|
19454
|
+
return cached2;
|
|
19246
19455
|
}
|
|
19247
19456
|
const probePromise = new Promise((resolve17, reject) => {
|
|
19248
19457
|
const args = [
|
|
@@ -19318,7 +19527,7 @@ var init_ffprobe = __esm({
|
|
|
19318
19527
|
});
|
|
19319
19528
|
|
|
19320
19529
|
// ../engine/src/utils/urlDownloader.ts
|
|
19321
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
19530
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync10, mkdirSync as mkdirSync7 } from "fs";
|
|
19322
19531
|
import { createHash } from "crypto";
|
|
19323
19532
|
import { join as join8, extname } from "path";
|
|
19324
19533
|
import { Readable } from "stream";
|
|
@@ -19331,19 +19540,19 @@ function getFilenameFromUrl(url) {
|
|
|
19331
19540
|
}
|
|
19332
19541
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
19333
19542
|
const cachedPath = downloadPathCache.get(url);
|
|
19334
|
-
if (cachedPath &&
|
|
19543
|
+
if (cachedPath && existsSync10(cachedPath)) {
|
|
19335
19544
|
return cachedPath;
|
|
19336
19545
|
}
|
|
19337
19546
|
const inFlight = inFlightDownloads.get(url);
|
|
19338
19547
|
if (inFlight) {
|
|
19339
19548
|
return inFlight;
|
|
19340
19549
|
}
|
|
19341
|
-
if (!
|
|
19550
|
+
if (!existsSync10(destDir)) {
|
|
19342
19551
|
mkdirSync7(destDir, { recursive: true });
|
|
19343
19552
|
}
|
|
19344
19553
|
const filename = getFilenameFromUrl(url);
|
|
19345
19554
|
const localPath = join8(destDir, filename);
|
|
19346
|
-
if (
|
|
19555
|
+
if (existsSync10(localPath)) {
|
|
19347
19556
|
downloadPathCache.set(url, localPath);
|
|
19348
19557
|
return localPath;
|
|
19349
19558
|
}
|
|
@@ -19391,7 +19600,7 @@ var init_urlDownloader = __esm({
|
|
|
19391
19600
|
|
|
19392
19601
|
// ../engine/src/services/videoFrameExtractor.ts
|
|
19393
19602
|
import { spawn as spawn6 } from "child_process";
|
|
19394
|
-
import { existsSync as
|
|
19603
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readdirSync as readdirSync4, rmSync as rmSync3 } from "fs";
|
|
19395
19604
|
import { join as join9 } from "path";
|
|
19396
19605
|
function parseVideoElements(html) {
|
|
19397
19606
|
const videos = [];
|
|
@@ -19420,7 +19629,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
19420
19629
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
19421
19630
|
const { fps, outputDir, quality = 95, format = "jpg" } = options;
|
|
19422
19631
|
const videoOutputDir = join9(outputDir, videoId);
|
|
19423
|
-
if (!
|
|
19632
|
+
if (!existsSync11(videoOutputDir)) mkdirSync8(videoOutputDir, { recursive: true });
|
|
19424
19633
|
const metadata = await extractVideoMetadata(videoPath);
|
|
19425
19634
|
const framePattern = `frame_%05d.${format}`;
|
|
19426
19635
|
const outputPattern = join9(videoOutputDir, framePattern);
|
|
@@ -19515,7 +19724,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config) {
|
|
|
19515
19724
|
mkdirSync8(downloadDir, { recursive: true });
|
|
19516
19725
|
videoPath = await downloadToTemp(videoPath, downloadDir);
|
|
19517
19726
|
}
|
|
19518
|
-
if (!
|
|
19727
|
+
if (!existsSync11(videoPath)) {
|
|
19519
19728
|
return { error: { videoId: video.id, error: `Video file not found: ${videoPath}` } };
|
|
19520
19729
|
}
|
|
19521
19730
|
let videoDuration = video.end - video.start;
|
|
@@ -19669,7 +19878,7 @@ var init_videoFrameExtractor = __esm({
|
|
|
19669
19878
|
}
|
|
19670
19879
|
cleanup() {
|
|
19671
19880
|
for (const video of this.videos.values()) {
|
|
19672
|
-
if (
|
|
19881
|
+
if (existsSync11(video.extracted.outputDir)) {
|
|
19673
19882
|
rmSync3(video.extracted.outputDir, { recursive: true, force: true });
|
|
19674
19883
|
}
|
|
19675
19884
|
}
|
|
@@ -19700,10 +19909,10 @@ function createFrameDataUriCache(cacheLimit) {
|
|
|
19700
19909
|
return dataUri;
|
|
19701
19910
|
}
|
|
19702
19911
|
async function get(framePath) {
|
|
19703
|
-
const
|
|
19704
|
-
if (
|
|
19705
|
-
remember(framePath,
|
|
19706
|
-
return
|
|
19912
|
+
const cached2 = cache.get(framePath);
|
|
19913
|
+
if (cached2) {
|
|
19914
|
+
remember(framePath, cached2);
|
|
19915
|
+
return cached2;
|
|
19707
19916
|
}
|
|
19708
19917
|
const existing = inFlight.get(framePath);
|
|
19709
19918
|
if (existing) {
|
|
@@ -19771,7 +19980,7 @@ var init_videoFrameInjector = __esm({
|
|
|
19771
19980
|
});
|
|
19772
19981
|
|
|
19773
19982
|
// ../engine/src/services/audioMixer.ts
|
|
19774
|
-
import { existsSync as
|
|
19983
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, rmSync as rmSync4 } from "fs";
|
|
19775
19984
|
import { join as join10, dirname as dirname5 } from "path";
|
|
19776
19985
|
function parseAudioElements(html) {
|
|
19777
19986
|
const elements = [];
|
|
@@ -19823,7 +20032,7 @@ function parseAudioElements(html) {
|
|
|
19823
20032
|
async function extractAudioFromVideo(videoPath, outputPath, options, signal, config) {
|
|
19824
20033
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
19825
20034
|
const outputDir = dirname5(outputPath);
|
|
19826
|
-
if (!
|
|
20035
|
+
if (!existsSync12(outputDir)) mkdirSync9(outputDir, { recursive: true });
|
|
19827
20036
|
const args = ["-i", videoPath];
|
|
19828
20037
|
if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
|
|
19829
20038
|
if (options?.duration !== void 0) args.push("-t", String(options.duration));
|
|
@@ -19850,7 +20059,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
|
|
|
19850
20059
|
async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config) {
|
|
19851
20060
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
19852
20061
|
const outputDir = dirname5(outputPath);
|
|
19853
|
-
if (!
|
|
20062
|
+
if (!existsSync12(outputDir)) mkdirSync9(outputDir, { recursive: true });
|
|
19854
20063
|
const args = [
|
|
19855
20064
|
"-ss",
|
|
19856
20065
|
String(mediaStart),
|
|
@@ -19886,7 +20095,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
|
|
|
19886
20095
|
async function generateSilence(outputPath, duration, signal, config) {
|
|
19887
20096
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
19888
20097
|
const outputDir = dirname5(outputPath);
|
|
19889
|
-
if (!
|
|
20098
|
+
if (!existsSync12(outputDir)) mkdirSync9(outputDir, { recursive: true });
|
|
19890
20099
|
const args = [
|
|
19891
20100
|
"-f",
|
|
19892
20101
|
"lavfi",
|
|
@@ -19929,7 +20138,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
|
|
|
19929
20138
|
};
|
|
19930
20139
|
}
|
|
19931
20140
|
const outputDir = dirname5(outputPath);
|
|
19932
|
-
if (!
|
|
20141
|
+
if (!existsSync12(outputDir)) mkdirSync9(outputDir, { recursive: true });
|
|
19933
20142
|
const inputs = [];
|
|
19934
20143
|
const filterParts = [];
|
|
19935
20144
|
tracks.forEach((track, i) => {
|
|
@@ -19990,7 +20199,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
19990
20199
|
const startMs = Date.now();
|
|
19991
20200
|
const tracks = [];
|
|
19992
20201
|
const errors = [];
|
|
19993
|
-
if (!
|
|
20202
|
+
if (!existsSync12(workDir)) mkdirSync9(workDir, { recursive: true });
|
|
19994
20203
|
await Promise.all(
|
|
19995
20204
|
elements.map(async (element) => {
|
|
19996
20205
|
if (signal?.aborted) {
|
|
@@ -20012,7 +20221,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
20012
20221
|
return;
|
|
20013
20222
|
}
|
|
20014
20223
|
}
|
|
20015
|
-
if (!
|
|
20224
|
+
if (!existsSync12(srcPath)) {
|
|
20016
20225
|
errors.push(`Source not found: ${element.id}`);
|
|
20017
20226
|
return;
|
|
20018
20227
|
}
|
|
@@ -20092,8 +20301,8 @@ var init_audioMixer = __esm({
|
|
|
20092
20301
|
});
|
|
20093
20302
|
|
|
20094
20303
|
// ../engine/src/services/parallelCoordinator.ts
|
|
20095
|
-
import { cpus, freemem, totalmem } from "os";
|
|
20096
|
-
import { existsSync as
|
|
20304
|
+
import { cpus as cpus2, freemem, totalmem as totalmem2 } from "os";
|
|
20305
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readdirSync as readdirSync5 } from "fs";
|
|
20097
20306
|
import { copyFile, rename } from "fs/promises";
|
|
20098
20307
|
import { join as join11 } from "path";
|
|
20099
20308
|
function calculateOptimalWorkers(totalFrames, requested, config) {
|
|
@@ -20111,9 +20320,9 @@ function calculateOptimalWorkers(totalFrames, requested, config) {
|
|
|
20111
20320
|
return Math.max(MIN_WORKERS, Math.min(effectiveMaxWorkers, requested));
|
|
20112
20321
|
}
|
|
20113
20322
|
if (totalFrames < MIN_FRAMES_PER_WORKER * 2) return 1;
|
|
20114
|
-
const cpuCount =
|
|
20323
|
+
const cpuCount = cpus2().length;
|
|
20115
20324
|
const cpuBasedWorkers = Math.max(1, cpuCount - 2);
|
|
20116
|
-
const totalMemoryMB = Math.round(
|
|
20325
|
+
const totalMemoryMB = Math.round(totalmem2() / (1024 * 1024));
|
|
20117
20326
|
const memoryBasedWorkers = Math.max(1, Math.floor(totalMemoryMB * 0.5 / MEMORY_PER_WORKER_MB));
|
|
20118
20327
|
const frameBasedWorkers = Math.floor(totalFrames / MIN_FRAMES_PER_WORKER);
|
|
20119
20328
|
const optimal = Math.min(cpuBasedWorkers, memoryBasedWorkers, frameBasedWorkers);
|
|
@@ -20146,7 +20355,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
|
|
|
20146
20355
|
async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCaptureHook, signal, onFrameCaptured, onFrameBuffer, config) {
|
|
20147
20356
|
const startTime = Date.now();
|
|
20148
20357
|
let framesCaptured = 0;
|
|
20149
|
-
if (!
|
|
20358
|
+
if (!existsSync13(task.outputDir)) mkdirSync10(task.outputDir, { recursive: true });
|
|
20150
20359
|
let session = null;
|
|
20151
20360
|
let perf;
|
|
20152
20361
|
try {
|
|
@@ -20236,11 +20445,11 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
|
|
|
20236
20445
|
return results;
|
|
20237
20446
|
}
|
|
20238
20447
|
async function mergeWorkerFrames(workDir, tasks, outputDir) {
|
|
20239
|
-
if (!
|
|
20448
|
+
if (!existsSync13(outputDir)) mkdirSync10(outputDir, { recursive: true });
|
|
20240
20449
|
let totalFrames = 0;
|
|
20241
20450
|
const sortedTasks = [...tasks].sort((a, b) => a.startFrame - b.startFrame);
|
|
20242
20451
|
for (const task of sortedTasks) {
|
|
20243
|
-
if (!
|
|
20452
|
+
if (!existsSync13(task.outputDir)) {
|
|
20244
20453
|
continue;
|
|
20245
20454
|
}
|
|
20246
20455
|
const files = readdirSync5(task.outputDir).filter((f) => f.startsWith("frame_") && (f.endsWith(".jpg") || f.endsWith(".png"))).sort();
|
|
@@ -20275,7 +20484,7 @@ var init_parallelCoordinator = __esm({
|
|
|
20275
20484
|
// ../engine/src/services/fileServer.ts
|
|
20276
20485
|
import { Hono } from "hono";
|
|
20277
20486
|
import { serve } from "@hono/node-server";
|
|
20278
|
-
import { readFileSync as
|
|
20487
|
+
import { readFileSync as readFileSync4, existsSync as existsSync14, statSync as statSync3 } from "fs";
|
|
20279
20488
|
import { join as join12, extname as extname2 } from "path";
|
|
20280
20489
|
var init_fileServer = __esm({
|
|
20281
20490
|
"../engine/src/services/fileServer.ts"() {
|
|
@@ -20306,7 +20515,7 @@ var init_src2 = __esm({
|
|
|
20306
20515
|
|
|
20307
20516
|
// ../producer/src/services/hyperframeRuntimeLoader.ts
|
|
20308
20517
|
import { createHash as createHash2 } from "crypto";
|
|
20309
|
-
import { existsSync as
|
|
20518
|
+
import { existsSync as existsSync15, readFileSync as readFileSync5 } from "fs";
|
|
20310
20519
|
import { dirname as dirname6, resolve as resolve4 } from "path";
|
|
20311
20520
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20312
20521
|
function resolveHyperframeManifestPath() {
|
|
@@ -20319,7 +20528,7 @@ function resolveHyperframeManifestPath() {
|
|
|
20319
20528
|
MODULE_RELATIVE_MANIFEST_PATH
|
|
20320
20529
|
];
|
|
20321
20530
|
for (const candidate of candidates) {
|
|
20322
|
-
if (
|
|
20531
|
+
if (existsSync15(candidate)) {
|
|
20323
20532
|
return candidate;
|
|
20324
20533
|
}
|
|
20325
20534
|
}
|
|
@@ -20330,12 +20539,12 @@ function getVerifiedHyperframeRuntimeSource() {
|
|
|
20330
20539
|
}
|
|
20331
20540
|
function resolveVerifiedHyperframeRuntime() {
|
|
20332
20541
|
const manifestPath = resolveHyperframeManifestPath();
|
|
20333
|
-
if (!
|
|
20542
|
+
if (!existsSync15(manifestPath)) {
|
|
20334
20543
|
throw new Error(
|
|
20335
20544
|
`[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
|
|
20336
20545
|
);
|
|
20337
20546
|
}
|
|
20338
|
-
const manifestRaw =
|
|
20547
|
+
const manifestRaw = readFileSync5(manifestPath, "utf8");
|
|
20339
20548
|
const manifest = JSON.parse(manifestRaw);
|
|
20340
20549
|
const runtimeFileName = manifest.artifacts?.iife;
|
|
20341
20550
|
if (!runtimeFileName || !manifest.sha256) {
|
|
@@ -20344,10 +20553,10 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
20344
20553
|
);
|
|
20345
20554
|
}
|
|
20346
20555
|
const runtimePath = resolve4(dirname6(manifestPath), runtimeFileName);
|
|
20347
|
-
if (!
|
|
20556
|
+
if (!existsSync15(runtimePath)) {
|
|
20348
20557
|
throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
|
|
20349
20558
|
}
|
|
20350
|
-
const runtimeSource =
|
|
20559
|
+
const runtimeSource = readFileSync5(runtimePath, "utf8");
|
|
20351
20560
|
const runtimeSha = createHash2("sha256").update(runtimeSource, "utf8").digest("hex");
|
|
20352
20561
|
if (runtimeSha !== manifest.sha256) {
|
|
20353
20562
|
throw new Error(
|
|
@@ -20386,7 +20595,7 @@ var init_hyperframeRuntimeLoader = __esm({
|
|
|
20386
20595
|
// ../producer/src/services/fileServer.ts
|
|
20387
20596
|
import { Hono as Hono2 } from "hono";
|
|
20388
20597
|
import { serve as serve2 } from "@hono/node-server";
|
|
20389
|
-
import { readFileSync as
|
|
20598
|
+
import { readFileSync as readFileSync6, existsSync as existsSync16, statSync as statSync4 } from "fs";
|
|
20390
20599
|
import { join as join13, extname as extname3 } from "path";
|
|
20391
20600
|
function stripEmbeddedRuntimeScripts2(html) {
|
|
20392
20601
|
if (!html) return html;
|
|
@@ -20458,21 +20667,21 @@ function createFileServer2(options) {
|
|
|
20458
20667
|
const relativePath = requestPath.replace(/^\//, "");
|
|
20459
20668
|
const compiledPath = compiledDir ? join13(compiledDir, relativePath) : null;
|
|
20460
20669
|
const hasCompiledFile = Boolean(
|
|
20461
|
-
compiledPath &&
|
|
20670
|
+
compiledPath && existsSync16(compiledPath) && statSync4(compiledPath).isFile()
|
|
20462
20671
|
);
|
|
20463
20672
|
const filePath = hasCompiledFile ? compiledPath : join13(projectDir, relativePath);
|
|
20464
|
-
if (!
|
|
20673
|
+
if (!existsSync16(filePath) || !statSync4(filePath).isFile()) {
|
|
20465
20674
|
return c2.text("Not found", 404);
|
|
20466
20675
|
}
|
|
20467
20676
|
const ext = extname3(filePath).toLowerCase();
|
|
20468
20677
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
20469
20678
|
if (ext === ".html") {
|
|
20470
|
-
const rawHtml =
|
|
20679
|
+
const rawHtml = readFileSync6(filePath, "utf-8");
|
|
20471
20680
|
const isIndex = relativePath === "index.html";
|
|
20472
20681
|
const html = isIndex ? injectScriptsIntoHtml(rawHtml, headScripts, bodyScripts, stripEmbeddedRuntime) : rawHtml;
|
|
20473
20682
|
return c2.text(html, 200, { "Content-Type": contentType });
|
|
20474
20683
|
}
|
|
20475
|
-
const content =
|
|
20684
|
+
const content = readFileSync6(filePath);
|
|
20476
20685
|
return new Response(content, {
|
|
20477
20686
|
status: 200,
|
|
20478
20687
|
headers: { "Content-Type": contentType }
|
|
@@ -20924,7 +21133,7 @@ var init_deterministicFonts = __esm({
|
|
|
20924
21133
|
});
|
|
20925
21134
|
|
|
20926
21135
|
// ../producer/src/services/htmlCompiler.ts
|
|
20927
|
-
import { readFileSync as
|
|
21136
|
+
import { readFileSync as readFileSync7, existsSync as existsSync17, mkdirSync as mkdirSync11 } from "fs";
|
|
20928
21137
|
import { join as join14, dirname as dirname7, resolve as resolve5 } from "path";
|
|
20929
21138
|
function dedupeElementsById(elements) {
|
|
20930
21139
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -20936,7 +21145,7 @@ function dedupeElementsById(elements) {
|
|
|
20936
21145
|
async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
|
|
20937
21146
|
let filePath = src;
|
|
20938
21147
|
if (isHttpUrl(src)) {
|
|
20939
|
-
if (!
|
|
21148
|
+
if (!existsSync17(downloadDir)) mkdirSync11(downloadDir, { recursive: true });
|
|
20940
21149
|
try {
|
|
20941
21150
|
filePath = await downloadToTemp(src, downloadDir);
|
|
20942
21151
|
} catch {
|
|
@@ -20945,7 +21154,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
20945
21154
|
} else if (!filePath.startsWith("/")) {
|
|
20946
21155
|
filePath = join14(baseDir, filePath);
|
|
20947
21156
|
}
|
|
20948
|
-
if (!
|
|
21157
|
+
if (!existsSync17(filePath)) {
|
|
20949
21158
|
return { duration: 0, resolvedPath: filePath };
|
|
20950
21159
|
}
|
|
20951
21160
|
const metadata = tagName19 === "video" ? await extractVideoMetadata(filePath) : await extractAudioMetadata(filePath);
|
|
@@ -21012,10 +21221,10 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
21012
21221
|
if (visited.has(filePath)) {
|
|
21013
21222
|
continue;
|
|
21014
21223
|
}
|
|
21015
|
-
if (!
|
|
21224
|
+
if (!existsSync17(filePath)) {
|
|
21016
21225
|
continue;
|
|
21017
21226
|
}
|
|
21018
|
-
const rawSubHtml =
|
|
21227
|
+
const rawSubHtml = readFileSync7(filePath, "utf-8");
|
|
21019
21228
|
const nestedVisited = new Set(visited);
|
|
21020
21229
|
nestedVisited.add(filePath);
|
|
21021
21230
|
workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
|
|
@@ -21209,8 +21418,8 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
21209
21418
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
21210
21419
|
if (!compHtml) {
|
|
21211
21420
|
const filePath = resolve5(projectDir, srcPath);
|
|
21212
|
-
if (
|
|
21213
|
-
compHtml =
|
|
21421
|
+
if (existsSync17(filePath)) {
|
|
21422
|
+
compHtml = readFileSync7(filePath, "utf-8");
|
|
21214
21423
|
}
|
|
21215
21424
|
}
|
|
21216
21425
|
if (!compHtml) {
|
|
@@ -21330,7 +21539,7 @@ ${html}
|
|
|
21330
21539
|
</html>`;
|
|
21331
21540
|
}
|
|
21332
21541
|
async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
21333
|
-
const rawHtml =
|
|
21542
|
+
const rawHtml = readFileSync7(htmlPath, "utf-8");
|
|
21334
21543
|
const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
|
|
21335
21544
|
rawHtml,
|
|
21336
21545
|
projectDir,
|
|
@@ -21518,10 +21727,10 @@ var init_logger = __esm({
|
|
|
21518
21727
|
|
|
21519
21728
|
// ../producer/src/services/renderOrchestrator.ts
|
|
21520
21729
|
import {
|
|
21521
|
-
existsSync as
|
|
21730
|
+
existsSync as existsSync18,
|
|
21522
21731
|
mkdirSync as mkdirSync12,
|
|
21523
21732
|
rmSync as rmSync5,
|
|
21524
|
-
readFileSync as
|
|
21733
|
+
readFileSync as readFileSync8,
|
|
21525
21734
|
writeFileSync as writeFileSync4,
|
|
21526
21735
|
copyFileSync as copyFileSync2,
|
|
21527
21736
|
appendFileSync
|
|
@@ -21683,28 +21892,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
21683
21892
|
};
|
|
21684
21893
|
job.startedAt = /* @__PURE__ */ new Date();
|
|
21685
21894
|
assertNotAborted();
|
|
21686
|
-
if (!
|
|
21895
|
+
if (!existsSync18(workDir)) mkdirSync12(workDir, { recursive: true });
|
|
21687
21896
|
if (job.config.debug) {
|
|
21688
21897
|
const logPath = join15(workDir, "render.log");
|
|
21689
21898
|
restoreLogger = installDebugLogger(logPath, log);
|
|
21690
21899
|
}
|
|
21691
21900
|
const entryFile = job.config.entryFile || "index.html";
|
|
21692
21901
|
let htmlPath = join15(projectDir, entryFile);
|
|
21693
|
-
if (!
|
|
21902
|
+
if (!existsSync18(htmlPath)) {
|
|
21694
21903
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
21695
21904
|
}
|
|
21696
21905
|
assertNotAborted();
|
|
21697
|
-
const rawEntry =
|
|
21906
|
+
const rawEntry = readFileSync8(htmlPath, "utf-8");
|
|
21698
21907
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
21699
21908
|
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
21700
21909
|
const projectIndexPath = join15(projectDir, "index.html");
|
|
21701
|
-
if (!
|
|
21910
|
+
if (!existsSync18(projectIndexPath)) {
|
|
21702
21911
|
throw new Error(
|
|
21703
21912
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
21704
21913
|
);
|
|
21705
21914
|
}
|
|
21706
21915
|
const standaloneHtml = extractStandaloneEntryFromIndex(
|
|
21707
|
-
|
|
21916
|
+
readFileSync8(projectIndexPath, "utf-8"),
|
|
21708
21917
|
entryFile
|
|
21709
21918
|
);
|
|
21710
21919
|
if (!standaloneHtml) {
|
|
@@ -21952,7 +22161,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
21952
22161
|
assertNotAborted();
|
|
21953
22162
|
}
|
|
21954
22163
|
const framesDir = join15(workDir, "captured-frames");
|
|
21955
|
-
if (!
|
|
22164
|
+
if (!existsSync18(framesDir)) mkdirSync12(framesDir, { recursive: true });
|
|
21956
22165
|
const captureOptions = {
|
|
21957
22166
|
width,
|
|
21958
22167
|
height,
|
|
@@ -22240,7 +22449,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
22240
22449
|
}
|
|
22241
22450
|
}
|
|
22242
22451
|
if (job.config.debug) {
|
|
22243
|
-
if (
|
|
22452
|
+
if (existsSync18(outputPath)) {
|
|
22244
22453
|
const debugOutput = join15(workDir, isWebm ? "output.webm" : "output.mp4");
|
|
22245
22454
|
copyFileSync2(outputPath, debugOutput);
|
|
22246
22455
|
}
|
|
@@ -22317,7 +22526,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
22317
22526
|
await safeCleanup(
|
|
22318
22527
|
"remove workDir (error)",
|
|
22319
22528
|
() => {
|
|
22320
|
-
if (
|
|
22529
|
+
if (existsSync18(workDir)) rmSync5(workDir, { recursive: true, force: true });
|
|
22321
22530
|
},
|
|
22322
22531
|
log
|
|
22323
22532
|
);
|
|
@@ -22379,7 +22588,7 @@ var init_lint = __esm({
|
|
|
22379
22588
|
});
|
|
22380
22589
|
|
|
22381
22590
|
// ../producer/src/services/hyperframeLint.ts
|
|
22382
|
-
import { existsSync as
|
|
22591
|
+
import { existsSync as existsSync19, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
22383
22592
|
import { resolve as resolve7, join as join16 } from "path";
|
|
22384
22593
|
function isStringRecord(value) {
|
|
22385
22594
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -22408,7 +22617,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
22408
22617
|
}
|
|
22409
22618
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
22410
22619
|
const absProjectDir = resolve7(projectDir);
|
|
22411
|
-
if (!
|
|
22620
|
+
if (!existsSync19(absProjectDir) || !statSync5(absProjectDir).isDirectory()) {
|
|
22412
22621
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
22413
22622
|
}
|
|
22414
22623
|
const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
|
|
@@ -22419,10 +22628,10 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
22419
22628
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
22420
22629
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
22421
22630
|
}
|
|
22422
|
-
if (
|
|
22631
|
+
if (existsSync19(absoluteEntryPath) && statSync5(absoluteEntryPath).isFile()) {
|
|
22423
22632
|
return {
|
|
22424
22633
|
entryFile,
|
|
22425
|
-
html:
|
|
22634
|
+
html: readFileSync9(absoluteEntryPath, "utf-8"),
|
|
22426
22635
|
source: "projectDir"
|
|
22427
22636
|
};
|
|
22428
22637
|
}
|
|
@@ -22493,7 +22702,7 @@ var init_paths = __esm({
|
|
|
22493
22702
|
|
|
22494
22703
|
// ../producer/src/server.ts
|
|
22495
22704
|
import {
|
|
22496
|
-
existsSync as
|
|
22705
|
+
existsSync as existsSync20,
|
|
22497
22706
|
mkdirSync as mkdirSync13,
|
|
22498
22707
|
statSync as statSync6,
|
|
22499
22708
|
mkdtempSync,
|
|
@@ -22523,11 +22732,11 @@ async function prepareRenderBody(body) {
|
|
|
22523
22732
|
const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
|
|
22524
22733
|
if (projectDir) {
|
|
22525
22734
|
const absProjectDir = resolve9(projectDir);
|
|
22526
|
-
if (!
|
|
22735
|
+
if (!existsSync20(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
|
|
22527
22736
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
22528
22737
|
}
|
|
22529
22738
|
const entry = options.entryFile || "index.html";
|
|
22530
|
-
if (!
|
|
22739
|
+
if (!existsSync20(resolve9(absProjectDir, entry))) {
|
|
22531
22740
|
return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
|
|
22532
22741
|
}
|
|
22533
22742
|
return { prepared: { input: { projectDir: absProjectDir, ...options } } };
|
|
@@ -22674,7 +22883,7 @@ function createRenderHandlers(options = {}) {
|
|
|
22674
22883
|
log
|
|
22675
22884
|
);
|
|
22676
22885
|
const outputDir = dirname9(absoluteOutputPath);
|
|
22677
|
-
if (!
|
|
22886
|
+
if (!existsSync20(outputDir)) mkdirSync13(outputDir, { recursive: true });
|
|
22678
22887
|
log.info("render started", {
|
|
22679
22888
|
requestId,
|
|
22680
22889
|
projectDir: input.projectDir,
|
|
@@ -22699,7 +22908,7 @@ function createRenderHandlers(options = {}) {
|
|
|
22699
22908
|
log.info(`render progress ${pct}%`, { requestId, stage: j2.currentStage, message });
|
|
22700
22909
|
}
|
|
22701
22910
|
});
|
|
22702
|
-
const fileSize =
|
|
22911
|
+
const fileSize = existsSync20(absoluteOutputPath) ? statSync6(absoluteOutputPath).size : 0;
|
|
22703
22912
|
const durationMs = Date.now() - t0;
|
|
22704
22913
|
const outputToken = store.register(absoluteOutputPath);
|
|
22705
22914
|
const outputUrl = `${outputUrlPrefix}/${outputToken}`;
|
|
@@ -22782,7 +22991,7 @@ function createRenderHandlers(options = {}) {
|
|
|
22782
22991
|
log
|
|
22783
22992
|
);
|
|
22784
22993
|
const outputDir = dirname9(absoluteOutputPath);
|
|
22785
|
-
if (!
|
|
22994
|
+
if (!existsSync20(outputDir)) mkdirSync13(outputDir, { recursive: true });
|
|
22786
22995
|
log.info("render-stream started", { requestId, projectDir: input.projectDir });
|
|
22787
22996
|
const job = createRenderJob({
|
|
22788
22997
|
fps: input.fps,
|
|
@@ -22816,7 +23025,7 @@ function createRenderHandlers(options = {}) {
|
|
|
22816
23025
|
},
|
|
22817
23026
|
abortController.signal
|
|
22818
23027
|
);
|
|
22819
|
-
const fileSize =
|
|
23028
|
+
const fileSize = existsSync20(absoluteOutputPath) ? statSync6(absoluteOutputPath).size : 0;
|
|
22820
23029
|
const outputToken = store.register(absoluteOutputPath);
|
|
22821
23030
|
const outputUrl = `${outputUrlPrefix}/${outputToken}`;
|
|
22822
23031
|
log.info("render-stream completed", { requestId, fileSize, perf: job.perfSummary ?? null });
|
|
@@ -22874,7 +23083,7 @@ function createRenderHandlers(options = {}) {
|
|
|
22874
23083
|
if (!artifact) {
|
|
22875
23084
|
return c2.json({ success: false, error: "Output artifact not found or expired" }, 404);
|
|
22876
23085
|
}
|
|
22877
|
-
if (!
|
|
23086
|
+
if (!existsSync20(artifact.path)) {
|
|
22878
23087
|
store.delete(token);
|
|
22879
23088
|
return c2.json({ success: false, error: "Output artifact file missing" }, 404);
|
|
22880
23089
|
}
|
|
@@ -23008,7 +23217,7 @@ __export(manager_exports2, {
|
|
|
23008
23217
|
setBrowserPath: () => setBrowserPath
|
|
23009
23218
|
});
|
|
23010
23219
|
import { execSync } from "child_process";
|
|
23011
|
-
import { existsSync as
|
|
23220
|
+
import { existsSync as existsSync21, rmSync as rmSync7 } from "fs";
|
|
23012
23221
|
import { homedir as homedir5 } from "os";
|
|
23013
23222
|
import { join as join19 } from "path";
|
|
23014
23223
|
import { Browser, detectBrowserPlatform, getInstalledBrowsers, install } from "@puppeteer/browsers";
|
|
@@ -23028,17 +23237,17 @@ function whichBinary2(name) {
|
|
|
23028
23237
|
}
|
|
23029
23238
|
}
|
|
23030
23239
|
function findFromEnv2() {
|
|
23031
|
-
if (_browserPathOverride &&
|
|
23240
|
+
if (_browserPathOverride && existsSync21(_browserPathOverride)) {
|
|
23032
23241
|
return { executablePath: _browserPathOverride, source: "env" };
|
|
23033
23242
|
}
|
|
23034
23243
|
const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
|
|
23035
|
-
if (envPath &&
|
|
23244
|
+
if (envPath && existsSync21(envPath)) {
|
|
23036
23245
|
return { executablePath: envPath, source: "env" };
|
|
23037
23246
|
}
|
|
23038
23247
|
return void 0;
|
|
23039
23248
|
}
|
|
23040
23249
|
async function findFromCache() {
|
|
23041
|
-
if (!
|
|
23250
|
+
if (!existsSync21(CACHE_DIR)) {
|
|
23042
23251
|
return void 0;
|
|
23043
23252
|
}
|
|
23044
23253
|
const installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR });
|
|
@@ -23050,7 +23259,7 @@ async function findFromCache() {
|
|
|
23050
23259
|
}
|
|
23051
23260
|
function findFromSystem2() {
|
|
23052
23261
|
for (const p of SYSTEM_CHROME_PATHS) {
|
|
23053
|
-
if (
|
|
23262
|
+
if (existsSync21(p)) {
|
|
23054
23263
|
return { executablePath: p, source: "system" };
|
|
23055
23264
|
}
|
|
23056
23265
|
}
|
|
@@ -23070,21 +23279,21 @@ async function findBrowser() {
|
|
|
23070
23279
|
async function ensureBrowser(options) {
|
|
23071
23280
|
const existing = await findBrowser();
|
|
23072
23281
|
if (existing) return existing;
|
|
23073
|
-
const
|
|
23074
|
-
if (!
|
|
23282
|
+
const platform4 = detectBrowserPlatform();
|
|
23283
|
+
if (!platform4) {
|
|
23075
23284
|
throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`);
|
|
23076
23285
|
}
|
|
23077
23286
|
const installed = await install({
|
|
23078
23287
|
cacheDir: CACHE_DIR,
|
|
23079
23288
|
browser: Browser.CHROMEHEADLESSSHELL,
|
|
23080
23289
|
buildId: CHROME_VERSION,
|
|
23081
|
-
platform:
|
|
23290
|
+
platform: platform4,
|
|
23082
23291
|
downloadProgressCallback: options?.onProgress
|
|
23083
23292
|
});
|
|
23084
23293
|
return { executablePath: installed.executablePath, source: "download" };
|
|
23085
23294
|
}
|
|
23086
23295
|
function clearBrowser() {
|
|
23087
|
-
if (!
|
|
23296
|
+
if (!existsSync21(CACHE_DIR)) {
|
|
23088
23297
|
return false;
|
|
23089
23298
|
}
|
|
23090
23299
|
rmSync7(CACHE_DIR, { recursive: true, force: true });
|
|
@@ -23112,18 +23321,18 @@ __export(studioServer_exports, {
|
|
|
23112
23321
|
});
|
|
23113
23322
|
import { Hono as Hono4 } from "hono";
|
|
23114
23323
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
23115
|
-
import { existsSync as
|
|
23324
|
+
import { existsSync as existsSync22, readFileSync as readFileSync10, readdirSync as readdirSync6, statSync as statSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync14 } from "fs";
|
|
23116
23325
|
import { resolve as resolve10, join as join20, sep as sep2, basename as basename2, dirname as dirname10, extname as extname4 } from "path";
|
|
23117
23326
|
function resolveDistDir() {
|
|
23118
23327
|
const builtPath = resolve10(__dirname, "studio");
|
|
23119
|
-
if (
|
|
23328
|
+
if (existsSync22(resolve10(builtPath, "index.html"))) return builtPath;
|
|
23120
23329
|
const devPath = resolve10(__dirname, "..", "..", "..", "studio", "dist");
|
|
23121
|
-
if (
|
|
23330
|
+
if (existsSync22(resolve10(devPath, "index.html"))) return devPath;
|
|
23122
23331
|
return builtPath;
|
|
23123
23332
|
}
|
|
23124
23333
|
function resolveRuntimePath() {
|
|
23125
23334
|
const builtPath = resolve10(__dirname, "hyperframe-runtime.js");
|
|
23126
|
-
if (
|
|
23335
|
+
if (existsSync22(builtPath)) return builtPath;
|
|
23127
23336
|
const devPath = resolve10(
|
|
23128
23337
|
__dirname,
|
|
23129
23338
|
"..",
|
|
@@ -23133,7 +23342,7 @@ function resolveRuntimePath() {
|
|
|
23133
23342
|
"dist",
|
|
23134
23343
|
"hyperframe.runtime.iife.js"
|
|
23135
23344
|
);
|
|
23136
|
-
if (
|
|
23345
|
+
if (existsSync22(devPath)) return devPath;
|
|
23137
23346
|
return builtPath;
|
|
23138
23347
|
}
|
|
23139
23348
|
function isSafePath(base, resolved) {
|
|
@@ -23157,27 +23366,27 @@ function walkDir(dir, prefix = "") {
|
|
|
23157
23366
|
return files;
|
|
23158
23367
|
}
|
|
23159
23368
|
function serveStaticFile(filePath) {
|
|
23160
|
-
if (!
|
|
23369
|
+
if (!existsSync22(filePath) || !statSync7(filePath).isFile()) return null;
|
|
23161
23370
|
const mime = getMimeType(filePath);
|
|
23162
|
-
const content =
|
|
23371
|
+
const content = readFileSync10(filePath);
|
|
23163
23372
|
return new Response(content, {
|
|
23164
23373
|
headers: { "Content-Type": mime, "Cache-Control": "no-store" }
|
|
23165
23374
|
});
|
|
23166
23375
|
}
|
|
23167
23376
|
function buildSubCompositionHtml(projectDir, compPath, runtimeUrl) {
|
|
23168
23377
|
const compFile = resolve10(projectDir, compPath);
|
|
23169
|
-
if (!isSafePath(projectDir, compFile) || !
|
|
23378
|
+
if (!isSafePath(projectDir, compFile) || !existsSync22(compFile) || !statSync7(compFile).isFile()) {
|
|
23170
23379
|
return null;
|
|
23171
23380
|
}
|
|
23172
|
-
let rawComp =
|
|
23381
|
+
let rawComp = readFileSync10(compFile, "utf-8");
|
|
23173
23382
|
const templateMatch = rawComp.match(/<template>([\s\S]*)<\/template>/i);
|
|
23174
23383
|
let content = (templateMatch ? templateMatch[1] : rawComp) ?? rawComp;
|
|
23175
23384
|
content = content.replace(
|
|
23176
23385
|
/(<[^>]*?)(data-composition-src=["']([^"']+)["'])([^>]*>)/g,
|
|
23177
23386
|
(_match, before2, srcAttr, src, after2) => {
|
|
23178
23387
|
const nestedFile = join20(projectDir, src);
|
|
23179
|
-
if (!
|
|
23180
|
-
const nestedRaw =
|
|
23388
|
+
if (!existsSync22(nestedFile)) return before2 + srcAttr + after2;
|
|
23389
|
+
const nestedRaw = readFileSync10(nestedFile, "utf-8");
|
|
23181
23390
|
const nestedTemplate = nestedRaw.match(/<template>([\s\S]*)<\/template>/i);
|
|
23182
23391
|
const nestedContent = (nestedTemplate ? nestedTemplate[1] : nestedRaw) ?? nestedRaw;
|
|
23183
23392
|
const styles = [];
|
|
@@ -23215,8 +23424,8 @@ function createStudioServer(options) {
|
|
|
23215
23424
|
const watcher = createProjectWatcher(projectDir);
|
|
23216
23425
|
const app = new Hono4();
|
|
23217
23426
|
app.get("/api/runtime.js", (c2) => {
|
|
23218
|
-
if (!
|
|
23219
|
-
return c2.body(
|
|
23427
|
+
if (!existsSync22(runtimePath)) return c2.text("runtime not built", 404);
|
|
23428
|
+
return c2.body(readFileSync10(runtimePath, "utf-8"), 200, {
|
|
23220
23429
|
"Content-Type": "text/javascript",
|
|
23221
23430
|
"Cache-Control": "no-store"
|
|
23222
23431
|
});
|
|
@@ -23251,8 +23460,8 @@ function createStudioServer(options) {
|
|
|
23251
23460
|
bundled = await bundleToSingleHtml2(projectDir);
|
|
23252
23461
|
} catch {
|
|
23253
23462
|
const file = join20(projectDir, "index.html");
|
|
23254
|
-
if (!
|
|
23255
|
-
bundled =
|
|
23463
|
+
if (!existsSync22(file)) return c2.text("not found", 404);
|
|
23464
|
+
bundled = readFileSync10(file, "utf-8");
|
|
23256
23465
|
}
|
|
23257
23466
|
const baseTag = `<base href="/api/projects/${projectId}/preview/">`;
|
|
23258
23467
|
if (bundled.includes("<head>")) {
|
|
@@ -23285,11 +23494,11 @@ function createStudioServer(options) {
|
|
|
23285
23494
|
c2.req.path.replace(`/api/projects/${id}/preview/`, "").split("?")[0] ?? ""
|
|
23286
23495
|
);
|
|
23287
23496
|
const file = resolve10(projectDir, subPath);
|
|
23288
|
-
if (!isSafePath(projectDir, file) || !
|
|
23497
|
+
if (!isSafePath(projectDir, file) || !existsSync22(file) || !statSync7(file).isFile()) {
|
|
23289
23498
|
return c2.text("not found", 404);
|
|
23290
23499
|
}
|
|
23291
23500
|
const mime = getMimeType(file);
|
|
23292
|
-
const content =
|
|
23501
|
+
const content = readFileSync10(file);
|
|
23293
23502
|
return new Response(content, {
|
|
23294
23503
|
headers: { "Content-Type": mime, "Cache-Control": "no-store" }
|
|
23295
23504
|
});
|
|
@@ -23299,10 +23508,10 @@ function createStudioServer(options) {
|
|
|
23299
23508
|
if (id !== projectId) return c2.json({ error: "not found" }, 404);
|
|
23300
23509
|
const filePath = decodeURIComponent(c2.req.path.replace(`/api/projects/${id}/files/`, ""));
|
|
23301
23510
|
const file = resolve10(projectDir, filePath);
|
|
23302
|
-
if (!isSafePath(projectDir, file) || !
|
|
23511
|
+
if (!isSafePath(projectDir, file) || !existsSync22(file)) {
|
|
23303
23512
|
return c2.text("not found", 404);
|
|
23304
23513
|
}
|
|
23305
|
-
const content =
|
|
23514
|
+
const content = readFileSync10(file, "utf-8");
|
|
23306
23515
|
return c2.json({ filename: filePath, content });
|
|
23307
23516
|
});
|
|
23308
23517
|
app.put("/api/projects/:id/files/*", async (c2) => {
|
|
@@ -23314,7 +23523,7 @@ function createStudioServer(options) {
|
|
|
23314
23523
|
return c2.json({ error: "forbidden" }, 403);
|
|
23315
23524
|
}
|
|
23316
23525
|
const dir = dirname10(file);
|
|
23317
|
-
if (!
|
|
23526
|
+
if (!existsSync22(dir)) mkdirSync14(dir, { recursive: true });
|
|
23318
23527
|
const body = await c2.req.text();
|
|
23319
23528
|
writeFileSync6(file, body, "utf-8");
|
|
23320
23529
|
return c2.json({ ok: true });
|
|
@@ -23326,7 +23535,7 @@ function createStudioServer(options) {
|
|
|
23326
23535
|
if (id !== projectId) return c2.json({ error: "not found" }, 404);
|
|
23327
23536
|
const jobId = Math.random().toString(36).slice(2, 10);
|
|
23328
23537
|
const outputDir = join20(projectDir, "renders");
|
|
23329
|
-
if (!
|
|
23538
|
+
if (!existsSync22(outputDir)) mkdirSync14(outputDir, { recursive: true });
|
|
23330
23539
|
const outputPath = join20(outputDir, `${projectId}.mp4`);
|
|
23331
23540
|
renderJobs.set(jobId, { status: "rendering", progress: 0, outputPath });
|
|
23332
23541
|
(async () => {
|
|
@@ -23340,7 +23549,11 @@ function createStudioServer(options) {
|
|
|
23340
23549
|
}
|
|
23341
23550
|
} catch {
|
|
23342
23551
|
}
|
|
23552
|
+
const { trackRenderComplete: trackRenderComplete2 } = await Promise.resolve().then(() => (init_events(), events_exports));
|
|
23553
|
+
const { bytesToMb: bytesToMb2 } = await Promise.resolve().then(() => (init_system(), system_exports));
|
|
23554
|
+
const { freemem: freemem5 } = await import("os");
|
|
23343
23555
|
const job = createRenderJob2({ fps: 30, quality: "standard" });
|
|
23556
|
+
const startTime = Date.now();
|
|
23344
23557
|
const onProgress = (j2) => {
|
|
23345
23558
|
const entry2 = renderJobs.get(jobId);
|
|
23346
23559
|
if (entry2) entry2.progress = j2.progress;
|
|
@@ -23351,7 +23564,41 @@ function createStudioServer(options) {
|
|
|
23351
23564
|
entry.status = "complete";
|
|
23352
23565
|
entry.progress = 100;
|
|
23353
23566
|
}
|
|
23567
|
+
const elapsed = Date.now() - startTime;
|
|
23568
|
+
const perf = job.perfSummary;
|
|
23569
|
+
const compositionDurationMs = perf ? Math.round(perf.compositionDurationSeconds * 1e3) : void 0;
|
|
23570
|
+
trackRenderComplete2({
|
|
23571
|
+
durationMs: elapsed,
|
|
23572
|
+
fps: 30,
|
|
23573
|
+
quality: "standard",
|
|
23574
|
+
workers: perf?.workers ?? 1,
|
|
23575
|
+
docker: false,
|
|
23576
|
+
gpu: false,
|
|
23577
|
+
compositionDurationMs,
|
|
23578
|
+
compositionWidth: perf?.resolution.width,
|
|
23579
|
+
compositionHeight: perf?.resolution.height,
|
|
23580
|
+
totalFrames: perf?.totalFrames,
|
|
23581
|
+
speedRatio: compositionDurationMs && compositionDurationMs > 0 && elapsed > 0 ? Math.round(compositionDurationMs / elapsed * 100) / 100 : void 0,
|
|
23582
|
+
captureAvgMs: perf?.captureAvgMs,
|
|
23583
|
+
capturePeakMs: perf?.capturePeakMs,
|
|
23584
|
+
peakMemoryMb: bytesToMb2(process.memoryUsage.rss()),
|
|
23585
|
+
memoryFreeMb: bytesToMb2(freemem5())
|
|
23586
|
+
});
|
|
23354
23587
|
} catch (err) {
|
|
23588
|
+
try {
|
|
23589
|
+
const { trackRenderError: trackRenderError2 } = await Promise.resolve().then(() => (init_events(), events_exports));
|
|
23590
|
+
const { bytesToMb: bytesToMb2 } = await Promise.resolve().then(() => (init_system(), system_exports));
|
|
23591
|
+
const { freemem: freemem5 } = await import("os");
|
|
23592
|
+
trackRenderError2({
|
|
23593
|
+
fps: 30,
|
|
23594
|
+
quality: "standard",
|
|
23595
|
+
docker: false,
|
|
23596
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
23597
|
+
peakMemoryMb: bytesToMb2(process.memoryUsage.rss()),
|
|
23598
|
+
memoryFreeMb: bytesToMb2(freemem5())
|
|
23599
|
+
});
|
|
23600
|
+
} catch {
|
|
23601
|
+
}
|
|
23355
23602
|
const entry = renderJobs.get(jobId);
|
|
23356
23603
|
if (entry) {
|
|
23357
23604
|
entry.status = "failed";
|
|
@@ -23385,10 +23632,10 @@ function createStudioServer(options) {
|
|
|
23385
23632
|
app.get("/api/render/:jobId/download", (c2) => {
|
|
23386
23633
|
const { jobId } = c2.req.param();
|
|
23387
23634
|
const job = renderJobs.get(jobId);
|
|
23388
|
-
if (!job?.outputPath || !
|
|
23635
|
+
if (!job?.outputPath || !existsSync22(job.outputPath)) {
|
|
23389
23636
|
return c2.json({ error: "not found" }, 404);
|
|
23390
23637
|
}
|
|
23391
|
-
const content =
|
|
23638
|
+
const content = readFileSync10(job.outputPath);
|
|
23392
23639
|
return new Response(content, {
|
|
23393
23640
|
headers: {
|
|
23394
23641
|
"Content-Type": "video/mp4",
|
|
@@ -23408,10 +23655,10 @@ function createStudioServer(options) {
|
|
|
23408
23655
|
});
|
|
23409
23656
|
app.get("*", (c2) => {
|
|
23410
23657
|
const indexPath = resolve10(studioDir, "index.html");
|
|
23411
|
-
if (!
|
|
23658
|
+
if (!existsSync22(indexPath)) {
|
|
23412
23659
|
return c2.text("Studio not found. Rebuild with: pnpm run build", 500);
|
|
23413
23660
|
}
|
|
23414
|
-
return c2.html(
|
|
23661
|
+
return c2.html(readFileSync10(indexPath, "utf-8"));
|
|
23415
23662
|
});
|
|
23416
23663
|
return { app, watcher };
|
|
23417
23664
|
}
|
|
@@ -23450,7 +23697,7 @@ __export(dev_exports, {
|
|
|
23450
23697
|
default: () => dev_default
|
|
23451
23698
|
});
|
|
23452
23699
|
import { spawn as spawn7 } from "child_process";
|
|
23453
|
-
import { existsSync as
|
|
23700
|
+
import { existsSync as existsSync23, lstatSync, symlinkSync, unlinkSync, readlinkSync, mkdirSync as mkdirSync15 } from "fs";
|
|
23454
23701
|
import { resolve as resolve11, dirname as dirname11, basename as basename3, join as join21 } from "path";
|
|
23455
23702
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
23456
23703
|
import { createRequire } from "module";
|
|
@@ -23496,7 +23743,7 @@ async function runDevMode(dir) {
|
|
|
23496
23743
|
mkdirSync15(projectsDir, { recursive: true });
|
|
23497
23744
|
let createdSymlink = false;
|
|
23498
23745
|
if (dir !== symlinkPath) {
|
|
23499
|
-
if (
|
|
23746
|
+
if (existsSync23(symlinkPath)) {
|
|
23500
23747
|
try {
|
|
23501
23748
|
const stat = lstatSync(symlinkPath);
|
|
23502
23749
|
if (stat.isSymbolicLink()) {
|
|
@@ -23508,7 +23755,7 @@ async function runDevMode(dir) {
|
|
|
23508
23755
|
} catch {
|
|
23509
23756
|
}
|
|
23510
23757
|
}
|
|
23511
|
-
if (!
|
|
23758
|
+
if (!existsSync23(symlinkPath)) {
|
|
23512
23759
|
symlinkSync(dir, symlinkPath, "dir");
|
|
23513
23760
|
createdSymlink = true;
|
|
23514
23761
|
}
|
|
@@ -23550,7 +23797,7 @@ async function runDevMode(dir) {
|
|
|
23550
23797
|
if (createdSymlink) {
|
|
23551
23798
|
process.on("exit", () => {
|
|
23552
23799
|
try {
|
|
23553
|
-
if (
|
|
23800
|
+
if (existsSync23(symlinkPath)) unlinkSync(symlinkPath);
|
|
23554
23801
|
} catch {
|
|
23555
23802
|
}
|
|
23556
23803
|
});
|
|
@@ -23577,12 +23824,12 @@ async function runLocalStudioMode(dir) {
|
|
|
23577
23824
|
mkdirSync15(projectsDir, { recursive: true });
|
|
23578
23825
|
let createdSymlink = false;
|
|
23579
23826
|
if (dir !== symlinkPath) {
|
|
23580
|
-
if (
|
|
23827
|
+
if (existsSync23(symlinkPath) && lstatSync(symlinkPath).isSymbolicLink()) {
|
|
23581
23828
|
if (resolve11(readlinkSync(symlinkPath)) !== resolve11(dir)) {
|
|
23582
23829
|
unlinkSync(symlinkPath);
|
|
23583
23830
|
}
|
|
23584
23831
|
}
|
|
23585
|
-
if (!
|
|
23832
|
+
if (!existsSync23(symlinkPath)) {
|
|
23586
23833
|
symlinkSync(dir, symlinkPath, "dir");
|
|
23587
23834
|
createdSymlink = true;
|
|
23588
23835
|
}
|
|
@@ -23621,7 +23868,7 @@ async function runLocalStudioMode(dir) {
|
|
|
23621
23868
|
if (createdSymlink) {
|
|
23622
23869
|
process.on("exit", () => {
|
|
23623
23870
|
try {
|
|
23624
|
-
if (
|
|
23871
|
+
if (existsSync23(symlinkPath)) unlinkSync(symlinkPath);
|
|
23625
23872
|
} catch {
|
|
23626
23873
|
}
|
|
23627
23874
|
});
|
|
@@ -23658,6 +23905,9 @@ async function runEmbeddedMode(dir, startPort) {
|
|
|
23658
23905
|
console.log(` ${c.dim("Project")} ${c.accent(projectName)}`);
|
|
23659
23906
|
console.log(` ${c.dim("Studio")} ${c.accent(url)}`);
|
|
23660
23907
|
console.log();
|
|
23908
|
+
console.log(` ${c.dim("Edit with your AI agent \u2014 it has HyperFrames skills installed.")}`);
|
|
23909
|
+
console.log(` ${c.dim("Changes reload automatically in the studio.")}`);
|
|
23910
|
+
console.log();
|
|
23661
23911
|
console.log(` ${c.dim("Press Ctrl+C to stop")}`);
|
|
23662
23912
|
console.log();
|
|
23663
23913
|
import("open").then((mod) => mod.default(`${url}#project/${projectName}`)).catch(() => {
|
|
@@ -23727,17 +23977,17 @@ var init_format = __esm({
|
|
|
23727
23977
|
});
|
|
23728
23978
|
|
|
23729
23979
|
// src/utils/project.ts
|
|
23730
|
-
import { existsSync as
|
|
23980
|
+
import { existsSync as existsSync24, statSync as statSync8 } from "fs";
|
|
23731
23981
|
import { resolve as resolve12, basename as basename4 } from "path";
|
|
23732
23982
|
function resolveProject(dirArg) {
|
|
23733
23983
|
const dir = resolve12(dirArg ?? ".");
|
|
23734
23984
|
const name = basename4(dir);
|
|
23735
23985
|
const indexPath = resolve12(dir, "index.html");
|
|
23736
|
-
if (!
|
|
23986
|
+
if (!existsSync24(dir) || !statSync8(dir).isDirectory()) {
|
|
23737
23987
|
errorBox("Not a directory: " + dir);
|
|
23738
23988
|
process.exit(1);
|
|
23739
23989
|
}
|
|
23740
|
-
if (!
|
|
23990
|
+
if (!existsSync24(indexPath)) {
|
|
23741
23991
|
errorBox(
|
|
23742
23992
|
"No composition found in " + dir,
|
|
23743
23993
|
"No index.html file found.",
|
|
@@ -23826,8 +24076,8 @@ var render_exports = {};
|
|
|
23826
24076
|
__export(render_exports, {
|
|
23827
24077
|
default: () => render_default
|
|
23828
24078
|
});
|
|
23829
|
-
import { existsSync as
|
|
23830
|
-
import { cpus as
|
|
24079
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync16, statSync as statSync9 } from "fs";
|
|
24080
|
+
import { cpus as cpus3, freemem as freemem3 } from "os";
|
|
23831
24081
|
import { resolve as resolve13, dirname as dirname12, join as join22 } from "path";
|
|
23832
24082
|
function defaultWorkerCount() {
|
|
23833
24083
|
return Math.max(1, Math.min(Math.floor(CPU_CORE_COUNT / 2), 4));
|
|
@@ -23835,8 +24085,9 @@ function defaultWorkerCount() {
|
|
|
23835
24085
|
async function renderDocker(projectDir, outputPath, options) {
|
|
23836
24086
|
const producer = await loadProducer();
|
|
23837
24087
|
const startTime = Date.now();
|
|
24088
|
+
let job;
|
|
23838
24089
|
try {
|
|
23839
|
-
|
|
24090
|
+
job = producer.createRenderJob({
|
|
23840
24091
|
fps: options.fps,
|
|
23841
24092
|
quality: options.quality,
|
|
23842
24093
|
format: options.format,
|
|
@@ -23845,24 +24096,10 @@ async function renderDocker(projectDir, outputPath, options) {
|
|
|
23845
24096
|
});
|
|
23846
24097
|
await producer.executeRenderJob(job, projectDir, outputPath);
|
|
23847
24098
|
} catch (error) {
|
|
23848
|
-
|
|
23849
|
-
fps: options.fps,
|
|
23850
|
-
quality: options.quality,
|
|
23851
|
-
docker: true
|
|
23852
|
-
});
|
|
23853
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
23854
|
-
errorBox("Render failed", message, "Check Docker is running: docker info");
|
|
23855
|
-
process.exit(1);
|
|
24099
|
+
handleRenderError(error, options, startTime, true, "Check Docker is running: docker info");
|
|
23856
24100
|
}
|
|
23857
24101
|
const elapsed = Date.now() - startTime;
|
|
23858
|
-
|
|
23859
|
-
durationMs: elapsed,
|
|
23860
|
-
fps: options.fps,
|
|
23861
|
-
quality: options.quality,
|
|
23862
|
-
workers: options.workers,
|
|
23863
|
-
docker: true,
|
|
23864
|
-
gpu: options.gpu
|
|
23865
|
-
});
|
|
24102
|
+
trackRenderMetrics(job, elapsed, options, true);
|
|
23866
24103
|
printRenderComplete(outputPath, elapsed, options.quiet);
|
|
23867
24104
|
}
|
|
23868
24105
|
async function renderLocal(projectDir, outputPath, options) {
|
|
@@ -23884,30 +24121,58 @@ async function renderLocal(projectDir, outputPath, options) {
|
|
|
23884
24121
|
try {
|
|
23885
24122
|
await producer.executeRenderJob(job, projectDir, outputPath, onProgress);
|
|
23886
24123
|
} catch (error) {
|
|
23887
|
-
|
|
23888
|
-
fps: options.fps,
|
|
23889
|
-
quality: options.quality,
|
|
23890
|
-
docker: false
|
|
23891
|
-
});
|
|
23892
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
23893
|
-
errorBox("Render failed", message, "Try --docker for containerized rendering");
|
|
23894
|
-
process.exit(1);
|
|
24124
|
+
handleRenderError(error, options, startTime, false, "Try --docker for containerized rendering");
|
|
23895
24125
|
}
|
|
23896
24126
|
const elapsed = Date.now() - startTime;
|
|
24127
|
+
trackRenderMetrics(job, elapsed, options, false);
|
|
24128
|
+
printRenderComplete(outputPath, elapsed, options.quiet);
|
|
24129
|
+
}
|
|
24130
|
+
function getMemorySnapshot() {
|
|
24131
|
+
return {
|
|
24132
|
+
peakMemoryMb: bytesToMb(process.memoryUsage.rss()),
|
|
24133
|
+
memoryFreeMb: bytesToMb(freemem3())
|
|
24134
|
+
};
|
|
24135
|
+
}
|
|
24136
|
+
function handleRenderError(error, options, startTime, docker, hint) {
|
|
24137
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
24138
|
+
trackRenderError({
|
|
24139
|
+
fps: options.fps,
|
|
24140
|
+
quality: options.quality,
|
|
24141
|
+
docker,
|
|
24142
|
+
workers: options.workers,
|
|
24143
|
+
gpu: options.gpu,
|
|
24144
|
+
elapsedMs: Date.now() - startTime,
|
|
24145
|
+
errorMessage: message,
|
|
24146
|
+
...getMemorySnapshot()
|
|
24147
|
+
});
|
|
24148
|
+
errorBox("Render failed", message, hint);
|
|
24149
|
+
process.exit(1);
|
|
24150
|
+
}
|
|
24151
|
+
function trackRenderMetrics(job, elapsedMs, options, docker) {
|
|
24152
|
+
const perf = job.perfSummary;
|
|
24153
|
+
const compositionDurationMs = perf ? Math.round(perf.compositionDurationSeconds * 1e3) : void 0;
|
|
24154
|
+
const speedRatio = compositionDurationMs && compositionDurationMs > 0 && elapsedMs > 0 ? Math.round(compositionDurationMs / elapsedMs * 100) / 100 : void 0;
|
|
23897
24155
|
trackRenderComplete({
|
|
23898
|
-
durationMs:
|
|
24156
|
+
durationMs: elapsedMs,
|
|
23899
24157
|
fps: options.fps,
|
|
23900
24158
|
quality: options.quality,
|
|
23901
24159
|
workers: options.workers,
|
|
23902
|
-
docker
|
|
23903
|
-
gpu: options.gpu
|
|
24160
|
+
docker,
|
|
24161
|
+
gpu: options.gpu,
|
|
24162
|
+
compositionDurationMs,
|
|
24163
|
+
compositionWidth: perf?.resolution.width,
|
|
24164
|
+
compositionHeight: perf?.resolution.height,
|
|
24165
|
+
totalFrames: perf?.totalFrames,
|
|
24166
|
+
speedRatio,
|
|
24167
|
+
captureAvgMs: perf?.captureAvgMs,
|
|
24168
|
+
capturePeakMs: perf?.capturePeakMs,
|
|
24169
|
+
...getMemorySnapshot()
|
|
23904
24170
|
});
|
|
23905
|
-
printRenderComplete(outputPath, elapsed, options.quiet);
|
|
23906
24171
|
}
|
|
23907
24172
|
function printRenderComplete(outputPath, elapsedMs, quiet) {
|
|
23908
24173
|
if (quiet) return;
|
|
23909
24174
|
let fileSize = "unknown";
|
|
23910
|
-
if (
|
|
24175
|
+
if (existsSync25(outputPath)) {
|
|
23911
24176
|
const stat = statSync9(outputPath);
|
|
23912
24177
|
fileSize = formatBytes(stat.size);
|
|
23913
24178
|
}
|
|
@@ -23927,10 +24192,11 @@ var init_render = __esm({
|
|
|
23927
24192
|
init_format();
|
|
23928
24193
|
init_progress();
|
|
23929
24194
|
init_events();
|
|
24195
|
+
init_system();
|
|
23930
24196
|
VALID_FPS = /* @__PURE__ */ new Set([24, 30, 60]);
|
|
23931
24197
|
VALID_QUALITY = /* @__PURE__ */ new Set(["draft", "standard", "high"]);
|
|
23932
24198
|
VALID_FORMAT = /* @__PURE__ */ new Set(["mp4", "webm"]);
|
|
23933
|
-
CPU_CORE_COUNT =
|
|
24199
|
+
CPU_CORE_COUNT = cpus3().length;
|
|
23934
24200
|
render_default = defineCommand({
|
|
23935
24201
|
meta: {
|
|
23936
24202
|
name: "render",
|
|
@@ -24101,7 +24367,7 @@ __export(transcribe_exports, {
|
|
|
24101
24367
|
transcribe: () => transcribe
|
|
24102
24368
|
});
|
|
24103
24369
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
24104
|
-
import { existsSync as
|
|
24370
|
+
import { existsSync as existsSync26, readFileSync as readFileSync11, mkdirSync as mkdirSync17, unlinkSync as unlinkSync2 } from "fs";
|
|
24105
24371
|
import { join as join23, extname as extname5 } from "path";
|
|
24106
24372
|
import { tmpdir as tmpdir2 } from "os";
|
|
24107
24373
|
function isAudioFile(filePath) {
|
|
@@ -24188,10 +24454,10 @@ async function transcribe(inputPath, outputDir, options) {
|
|
|
24188
24454
|
{ stdio: "ignore", timeout: 3e5 }
|
|
24189
24455
|
);
|
|
24190
24456
|
const transcriptPath = `${outputBase}.json`;
|
|
24191
|
-
if (!
|
|
24457
|
+
if (!existsSync26(transcriptPath)) {
|
|
24192
24458
|
throw new Error("Whisper did not produce output. Check the input file.");
|
|
24193
24459
|
}
|
|
24194
|
-
const transcript = JSON.parse(
|
|
24460
|
+
const transcript = JSON.parse(readFileSync11(transcriptPath, "utf-8"));
|
|
24195
24461
|
const segments = transcript.transcription ?? [];
|
|
24196
24462
|
let wordCount = 0;
|
|
24197
24463
|
let maxEnd = 0;
|
|
@@ -24230,12 +24496,12 @@ __export(init_exports, {
|
|
|
24230
24496
|
default: () => init_default
|
|
24231
24497
|
});
|
|
24232
24498
|
import {
|
|
24233
|
-
existsSync as
|
|
24499
|
+
existsSync as existsSync27,
|
|
24234
24500
|
mkdirSync as mkdirSync18,
|
|
24235
24501
|
copyFileSync as copyFileSync3,
|
|
24236
24502
|
cpSync as cpSync2,
|
|
24237
24503
|
writeFileSync as writeFileSync7,
|
|
24238
|
-
readFileSync as
|
|
24504
|
+
readFileSync as readFileSync12,
|
|
24239
24505
|
readdirSync as readdirSync7
|
|
24240
24506
|
} from "fs";
|
|
24241
24507
|
import { resolve as resolve14, basename as basename5, join as join24, dirname as dirname13 } from "path";
|
|
@@ -24361,7 +24627,7 @@ function resolveAssetDir(devSegments, builtSegments) {
|
|
|
24361
24627
|
const base = dirname13(fileURLToPath5(import.meta.url));
|
|
24362
24628
|
const devPath = resolve14(base, ...devSegments);
|
|
24363
24629
|
const builtPath = resolve14(base, ...builtSegments);
|
|
24364
|
-
return
|
|
24630
|
+
return existsSync27(devPath) ? devPath : builtPath;
|
|
24365
24631
|
}
|
|
24366
24632
|
function getStaticTemplateDir(templateId) {
|
|
24367
24633
|
return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
|
|
@@ -24375,7 +24641,7 @@ function getBundledSkillsDir() {
|
|
|
24375
24641
|
function patchVideoSrc(dir, videoFilename, durationSeconds) {
|
|
24376
24642
|
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));
|
|
24377
24643
|
for (const file of htmlFiles) {
|
|
24378
|
-
let content =
|
|
24644
|
+
let content = readFileSync12(file, "utf-8");
|
|
24379
24645
|
if (videoFilename) {
|
|
24380
24646
|
content = content.replaceAll("__VIDEO_SRC__", videoFilename);
|
|
24381
24647
|
} else {
|
|
@@ -24390,7 +24656,7 @@ function patchVideoSrc(dir, videoFilename, durationSeconds) {
|
|
|
24390
24656
|
}
|
|
24391
24657
|
}
|
|
24392
24658
|
function patchTranscript(dir, transcriptPath) {
|
|
24393
|
-
const raw = JSON.parse(
|
|
24659
|
+
const raw = JSON.parse(readFileSync12(transcriptPath, "utf-8"));
|
|
24394
24660
|
const words = [];
|
|
24395
24661
|
for (const seg of raw.transcription ?? []) {
|
|
24396
24662
|
for (const token of seg.tokens ?? []) {
|
|
@@ -24414,7 +24680,7 @@ function patchTranscript(dir, transcriptPath) {
|
|
|
24414
24680
|
const wordsJson = JSON.stringify(words, null, 10).replace(/^\[/, "[").replace(/\n {10}/g, "\n ");
|
|
24415
24681
|
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));
|
|
24416
24682
|
for (const file of htmlFiles) {
|
|
24417
|
-
let content =
|
|
24683
|
+
let content = readFileSync12(file, "utf-8");
|
|
24418
24684
|
const scriptBlocks = content.match(/<script>[\s\S]*?<\/script>/g) ?? [];
|
|
24419
24685
|
let scriptMatch = null;
|
|
24420
24686
|
let transcriptMatch = null;
|
|
@@ -24463,8 +24729,16 @@ async function handleVideoFile(videoPath, destDir, interactive) {
|
|
|
24463
24729
|
const transcode = await Jt({
|
|
24464
24730
|
message: "Transcode to H.264 MP4 for browser playback?",
|
|
24465
24731
|
options: [
|
|
24466
|
-
{
|
|
24467
|
-
|
|
24732
|
+
{
|
|
24733
|
+
value: "yes",
|
|
24734
|
+
label: "Yes, transcode",
|
|
24735
|
+
hint: "converts to H.264 MP4"
|
|
24736
|
+
},
|
|
24737
|
+
{
|
|
24738
|
+
value: "no",
|
|
24739
|
+
label: "No, keep original",
|
|
24740
|
+
hint: "video won't play in browser"
|
|
24741
|
+
}
|
|
24468
24742
|
]
|
|
24469
24743
|
});
|
|
24470
24744
|
if (Ct(transcode)) {
|
|
@@ -24523,7 +24797,7 @@ function scaffoldProject(destDir, name, templateId, localVideoName, durationSeco
|
|
|
24523
24797
|
"utf-8"
|
|
24524
24798
|
);
|
|
24525
24799
|
const sharedDir = getSharedTemplateDir();
|
|
24526
|
-
if (
|
|
24800
|
+
if (existsSync27(sharedDir)) {
|
|
24527
24801
|
for (const entry of readdirSync7(sharedDir, { withFileTypes: true })) {
|
|
24528
24802
|
const src = join24(sharedDir, entry.name);
|
|
24529
24803
|
const dest = resolve14(destDir, entry.name);
|
|
@@ -24533,11 +24807,11 @@ function scaffoldProject(destDir, name, templateId, localVideoName, durationSeco
|
|
|
24533
24807
|
}
|
|
24534
24808
|
}
|
|
24535
24809
|
const skillsSrcDir = getBundledSkillsDir();
|
|
24536
|
-
if (
|
|
24537
|
-
const projectSkills = ["compose
|
|
24810
|
+
if (existsSync27(skillsSrcDir)) {
|
|
24811
|
+
const projectSkills = ["hyperframes-compose", "hyperframes-captions"];
|
|
24538
24812
|
for (const skill of projectSkills) {
|
|
24539
24813
|
const src = join24(skillsSrcDir, skill);
|
|
24540
|
-
if (
|
|
24814
|
+
if (existsSync27(src)) {
|
|
24541
24815
|
const dest = resolve14(destDir, ".claude", "skills", skill);
|
|
24542
24816
|
mkdirSync18(dest, { recursive: true });
|
|
24543
24817
|
cpSync2(src, dest, { recursive: true });
|
|
@@ -24550,7 +24824,11 @@ async function nextStepLoop(destDir) {
|
|
|
24550
24824
|
const next = await Jt({
|
|
24551
24825
|
message: "What do you want to do?",
|
|
24552
24826
|
options: [
|
|
24553
|
-
{
|
|
24827
|
+
{
|
|
24828
|
+
value: "dev",
|
|
24829
|
+
label: "Open in studio",
|
|
24830
|
+
hint: "full editor with timeline"
|
|
24831
|
+
},
|
|
24554
24832
|
{ value: "render", label: "Render to MP4", hint: "export video now" },
|
|
24555
24833
|
{ value: "done", label: "Done for now" }
|
|
24556
24834
|
]
|
|
@@ -24599,10 +24877,10 @@ var init_init = __esm({
|
|
|
24599
24877
|
description: `Scaffold a new composition project
|
|
24600
24878
|
|
|
24601
24879
|
Examples:
|
|
24602
|
-
hyperframes init my-video
|
|
24603
|
-
hyperframes init
|
|
24604
|
-
hyperframes init my-video --
|
|
24605
|
-
hyperframes init --
|
|
24880
|
+
hyperframes init my-video # interactive wizard
|
|
24881
|
+
hyperframes init my-video --template warm-grain # pick a template
|
|
24882
|
+
hyperframes init my-video --video video.mp4 # with video file
|
|
24883
|
+
hyperframes init my-video --non-interactive # skip prompts (CI/agents)`
|
|
24606
24884
|
},
|
|
24607
24885
|
args: {
|
|
24608
24886
|
name: { type: "positional", description: "Project name", required: false },
|
|
@@ -24611,11 +24889,28 @@ Examples:
|
|
|
24611
24889
|
description: `Template (${ALL_TEMPLATE_IDS.join(", ")})`,
|
|
24612
24890
|
alias: "t"
|
|
24613
24891
|
},
|
|
24614
|
-
video: {
|
|
24615
|
-
|
|
24616
|
-
|
|
24617
|
-
|
|
24618
|
-
|
|
24892
|
+
video: {
|
|
24893
|
+
type: "string",
|
|
24894
|
+
description: "Path to a video file (MP4, WebM, MOV)",
|
|
24895
|
+
alias: "V"
|
|
24896
|
+
},
|
|
24897
|
+
audio: {
|
|
24898
|
+
type: "string",
|
|
24899
|
+
description: "Path to an audio file (MP3, WAV, M4A)",
|
|
24900
|
+
alias: "a"
|
|
24901
|
+
},
|
|
24902
|
+
"skip-skills": {
|
|
24903
|
+
type: "boolean",
|
|
24904
|
+
description: "Skip AI coding skills installation"
|
|
24905
|
+
},
|
|
24906
|
+
"skip-transcribe": {
|
|
24907
|
+
type: "boolean",
|
|
24908
|
+
description: "Skip whisper transcription"
|
|
24909
|
+
},
|
|
24910
|
+
"non-interactive": {
|
|
24911
|
+
type: "boolean",
|
|
24912
|
+
description: "Disable interactive prompts (for CI/agents)"
|
|
24913
|
+
}
|
|
24619
24914
|
},
|
|
24620
24915
|
async run({ args }) {
|
|
24621
24916
|
const templateFlag = args.template;
|
|
@@ -24623,24 +24918,19 @@ Examples:
|
|
|
24623
24918
|
const audioFlag = args.audio;
|
|
24624
24919
|
const skipSkills = args["skip-skills"] === true;
|
|
24625
24920
|
const skipTranscribe = args["skip-transcribe"] === true;
|
|
24626
|
-
const
|
|
24627
|
-
|
|
24628
|
-
|
|
24629
|
-
|
|
24630
|
-
|
|
24631
|
-
console.error(`
|
|
24632
|
-
Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
24633
|
-
process.exit(1);
|
|
24634
|
-
}
|
|
24635
|
-
if (!ALL_TEMPLATE_IDS.includes(templateFlag)) {
|
|
24636
|
-
console.error(c.error(`Unknown template: ${templateFlag}`));
|
|
24921
|
+
const nonInteractive = args["non-interactive"] === true;
|
|
24922
|
+
const interactive = !nonInteractive && process.stdout.isTTY === true;
|
|
24923
|
+
if (!interactive) {
|
|
24924
|
+
const resolvedTemplate = templateFlag ?? "blank";
|
|
24925
|
+
if (!ALL_TEMPLATE_IDS.includes(resolvedTemplate)) {
|
|
24926
|
+
console.error(c.error(`Unknown template: ${resolvedTemplate}`));
|
|
24637
24927
|
console.error(`Available: ${ALL_TEMPLATE_IDS.join(", ")}`);
|
|
24638
24928
|
process.exit(1);
|
|
24639
24929
|
}
|
|
24640
|
-
const templateId2 =
|
|
24930
|
+
const templateId2 = resolvedTemplate;
|
|
24641
24931
|
const name2 = args.name ?? "my-video";
|
|
24642
24932
|
const destDir2 = resolve14(name2);
|
|
24643
|
-
if (
|
|
24933
|
+
if (existsSync27(destDir2) && readdirSync7(destDir2).length > 0) {
|
|
24644
24934
|
console.error(c.error(`Directory already exists and is not empty: ${name2}`));
|
|
24645
24935
|
process.exit(1);
|
|
24646
24936
|
}
|
|
@@ -24650,7 +24940,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24650
24940
|
let sourceFilePath2;
|
|
24651
24941
|
if (videoFlag) {
|
|
24652
24942
|
const videoPath = resolve14(videoFlag);
|
|
24653
|
-
if (!
|
|
24943
|
+
if (!existsSync27(videoPath)) {
|
|
24654
24944
|
console.error(c.error(`Video file not found: ${videoFlag}`));
|
|
24655
24945
|
process.exit(1);
|
|
24656
24946
|
}
|
|
@@ -24664,7 +24954,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24664
24954
|
}
|
|
24665
24955
|
if (audioFlag) {
|
|
24666
24956
|
const audioPath = resolve14(audioFlag);
|
|
24667
|
-
if (!
|
|
24957
|
+
if (!existsSync27(audioPath)) {
|
|
24668
24958
|
console.error(c.error(`Audio file not found: ${audioFlag}`));
|
|
24669
24959
|
process.exit(1);
|
|
24670
24960
|
}
|
|
@@ -24691,7 +24981,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24691
24981
|
scaffoldProject(destDir2, basename5(destDir2), templateId2, localVideoName2, videoDuration2);
|
|
24692
24982
|
trackInitTemplate(templateId2);
|
|
24693
24983
|
const transcriptFile2 = resolve14(destDir2, "transcript.json");
|
|
24694
|
-
if (
|
|
24984
|
+
if (existsSync27(transcriptFile2)) {
|
|
24695
24985
|
patchTranscript(destDir2, transcriptFile2);
|
|
24696
24986
|
}
|
|
24697
24987
|
if (!skipSkills) {
|
|
@@ -24702,23 +24992,22 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24702
24992
|
console.log(` ${c.accent(f)}`);
|
|
24703
24993
|
}
|
|
24704
24994
|
console.log();
|
|
24705
|
-
console.log("
|
|
24706
|
-
console.log(
|
|
24707
|
-
|
|
24708
|
-
);
|
|
24709
|
-
console.log(
|
|
24710
|
-
` ${c.accent(`cd ${name2}`)} && ${c.accent("npx hyperframes render")} ${c.dim("# render to MP4")}`
|
|
24711
|
-
);
|
|
24995
|
+
console.log("Get started:");
|
|
24996
|
+
console.log();
|
|
24997
|
+
console.log(` ${c.accent("1.")} Open this project with your AI coding agent:`);
|
|
24712
24998
|
console.log(
|
|
24713
|
-
`
|
|
24999
|
+
` ${c.accent(`cd ${name2}`)} then start ${c.accent("Claude Code")}, ${c.accent("Cursor")}, or your preferred agent`
|
|
24714
25000
|
);
|
|
24715
25001
|
console.log(
|
|
24716
|
-
`
|
|
25002
|
+
` ${c.dim("AI skills are installed \u2014 your agent knows how to create and edit compositions.")}`
|
|
24717
25003
|
);
|
|
24718
25004
|
console.log();
|
|
24719
|
-
console.log(
|
|
24720
|
-
|
|
24721
|
-
);
|
|
25005
|
+
console.log(` ${c.accent("2.")} Preview in the browser:`);
|
|
25006
|
+
console.log(` ${c.accent(`cd ${name2}`)} && ${c.accent("npx hyperframes dev")}`);
|
|
25007
|
+
console.log();
|
|
25008
|
+
console.log(` ${c.accent("3.")} Render to MP4 when ready:`);
|
|
25009
|
+
console.log(` ${c.accent(`cd ${name2}`)} && ${c.accent("npx hyperframes render")}`);
|
|
25010
|
+
console.log();
|
|
24722
25011
|
console.log(` ${c.dim("Full docs: hyperframes.heygen.com")}`);
|
|
24723
25012
|
return;
|
|
24724
25013
|
}
|
|
@@ -24740,7 +25029,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24740
25029
|
name = nameResult;
|
|
24741
25030
|
}
|
|
24742
25031
|
const destDir = resolve14(name);
|
|
24743
|
-
if (
|
|
25032
|
+
if (existsSync27(destDir) && readdirSync7(destDir).length > 0) {
|
|
24744
25033
|
const overwrite = await Rt({
|
|
24745
25034
|
message: `Directory ${c.accent(name)} already exists and is not empty. Overwrite?`,
|
|
24746
25035
|
initialValue: false
|
|
@@ -24756,7 +25045,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24756
25045
|
let isAudioOnly = false;
|
|
24757
25046
|
if (videoFlag) {
|
|
24758
25047
|
const videoPath = resolve14(videoFlag);
|
|
24759
|
-
if (!
|
|
25048
|
+
if (!existsSync27(videoPath)) {
|
|
24760
25049
|
R2.error(`File not found: ${videoFlag}`);
|
|
24761
25050
|
Nt("Setup cancelled.");
|
|
24762
25051
|
process.exit(1);
|
|
@@ -24772,7 +25061,11 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24772
25061
|
options: [
|
|
24773
25062
|
{ value: "video", label: "Video", hint: "MP4, WebM, MOV" },
|
|
24774
25063
|
{ value: "audio", label: "Audio only", hint: "MP3, WAV, M4A" },
|
|
24775
|
-
{
|
|
25064
|
+
{
|
|
25065
|
+
value: "no",
|
|
25066
|
+
label: "No",
|
|
25067
|
+
hint: "Start with motion graphics or text"
|
|
25068
|
+
}
|
|
24776
25069
|
],
|
|
24777
25070
|
initialValue: "no"
|
|
24778
25071
|
});
|
|
@@ -24787,7 +25080,7 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24787
25080
|
validate(val) {
|
|
24788
25081
|
const trimmed = val?.trim();
|
|
24789
25082
|
if (!trimmed) return "Please enter a file path";
|
|
24790
|
-
if (!
|
|
25083
|
+
if (!existsSync27(resolve14(trimmed))) return "File not found";
|
|
24791
25084
|
return void 0;
|
|
24792
25085
|
}
|
|
24793
25086
|
});
|
|
@@ -24829,7 +25122,9 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24829
25122
|
await ensureWhisper2({
|
|
24830
25123
|
onProgress: (msg) => spin.message(msg)
|
|
24831
25124
|
});
|
|
24832
|
-
await ensureModel2(void 0, {
|
|
25125
|
+
await ensureModel2(void 0, {
|
|
25126
|
+
onProgress: (msg) => spin.message(msg)
|
|
25127
|
+
});
|
|
24833
25128
|
spin.message("Transcribing audio...");
|
|
24834
25129
|
const { transcribe: runTranscribe } = await Promise.resolve().then(() => (init_transcribe(), transcribe_exports));
|
|
24835
25130
|
const transcribeResult = await runTranscribe(sourceFilePath, destDir, {
|
|
@@ -24845,25 +25140,33 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24845
25140
|
}
|
|
24846
25141
|
}
|
|
24847
25142
|
}
|
|
24848
|
-
|
|
24849
|
-
|
|
24850
|
-
|
|
24851
|
-
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
|
|
24855
|
-
|
|
24856
|
-
|
|
24857
|
-
|
|
24858
|
-
|
|
24859
|
-
|
|
24860
|
-
|
|
25143
|
+
let templateId;
|
|
25144
|
+
if (templateFlag && ALL_TEMPLATE_IDS.includes(templateFlag)) {
|
|
25145
|
+
templateId = templateFlag;
|
|
25146
|
+
} else {
|
|
25147
|
+
if (templateFlag) {
|
|
25148
|
+
R2.warn(`Unknown template "${templateFlag}" \u2014 pick from the list below`);
|
|
25149
|
+
}
|
|
25150
|
+
const defaultTemplate = isAudioOnly ? "warm-grain" : "blank";
|
|
25151
|
+
const templateResult = await Jt({
|
|
25152
|
+
message: "Pick a template",
|
|
25153
|
+
options: TEMPLATES.map((t2) => ({
|
|
25154
|
+
value: t2.id,
|
|
25155
|
+
label: t2.label,
|
|
25156
|
+
hint: t2.hint
|
|
25157
|
+
})),
|
|
25158
|
+
initialValue: defaultTemplate
|
|
25159
|
+
});
|
|
25160
|
+
if (Ct(templateResult)) {
|
|
25161
|
+
Nt("Setup cancelled.");
|
|
25162
|
+
process.exit(0);
|
|
25163
|
+
}
|
|
25164
|
+
templateId = templateResult;
|
|
24861
25165
|
}
|
|
24862
|
-
const templateId = templateResult;
|
|
24863
25166
|
scaffoldProject(destDir, name, templateId, localVideoName, videoDuration);
|
|
24864
25167
|
trackInitTemplate(templateId);
|
|
24865
25168
|
const transcriptFile = resolve14(destDir, "transcript.json");
|
|
24866
|
-
if (
|
|
25169
|
+
if (existsSync27(transcriptFile)) {
|
|
24867
25170
|
patchTranscript(destDir, transcriptFile);
|
|
24868
25171
|
}
|
|
24869
25172
|
if (!skipSkills) {
|
|
@@ -24871,6 +25174,10 @@ Example: hyperframes init my-video --template blank --video video.mp4`);
|
|
|
24871
25174
|
}
|
|
24872
25175
|
const files = readdirSync7(destDir);
|
|
24873
25176
|
Vt2(files.map((f) => c.accent(f)).join("\n"), c.success(`Created ${name}/`));
|
|
25177
|
+
R2.message(
|
|
25178
|
+
`${c.dim("Tip:")} Open this project with ${c.accent("Claude Code")}, ${c.accent("Cursor")}, or your preferred AI agent.
|
|
25179
|
+
${c.dim(" AI skills are installed \u2014 your agent knows how to create and edit compositions.")}`
|
|
25180
|
+
);
|
|
24874
25181
|
await nextStepLoop(destDir);
|
|
24875
25182
|
}
|
|
24876
25183
|
});
|
|
@@ -24882,7 +25189,7 @@ var lint_exports = {};
|
|
|
24882
25189
|
__export(lint_exports, {
|
|
24883
25190
|
default: () => lint_default
|
|
24884
25191
|
});
|
|
24885
|
-
import { readFileSync as
|
|
25192
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
24886
25193
|
var lint_default;
|
|
24887
25194
|
var init_lint2 = __esm({
|
|
24888
25195
|
"src/commands/lint.ts"() {
|
|
@@ -24900,7 +25207,7 @@ var init_lint2 = __esm({
|
|
|
24900
25207
|
},
|
|
24901
25208
|
async run({ args }) {
|
|
24902
25209
|
const project = resolveProject(args.dir);
|
|
24903
|
-
const html =
|
|
25210
|
+
const html = readFileSync13(project.indexPath, "utf-8");
|
|
24904
25211
|
const result = lintHyperframeHtml(html, { filePath: project.indexPath });
|
|
24905
25212
|
if (args.json) {
|
|
24906
25213
|
console.log(JSON.stringify(withMeta(result), null, 2));
|
|
@@ -24949,7 +25256,7 @@ var info_exports = {};
|
|
|
24949
25256
|
__export(info_exports, {
|
|
24950
25257
|
default: () => info_default
|
|
24951
25258
|
});
|
|
24952
|
-
import { readFileSync as
|
|
25259
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync8, statSync as statSync10 } from "fs";
|
|
24953
25260
|
import { join as join25 } from "path";
|
|
24954
25261
|
function totalSize(dir) {
|
|
24955
25262
|
let total = 0;
|
|
@@ -24982,7 +25289,7 @@ var init_info = __esm({
|
|
|
24982
25289
|
},
|
|
24983
25290
|
async run({ args }) {
|
|
24984
25291
|
const project = resolveProject(args.dir);
|
|
24985
|
-
const html =
|
|
25292
|
+
const html = readFileSync14(project.indexPath, "utf-8");
|
|
24986
25293
|
ensureDOMParser();
|
|
24987
25294
|
const parsed = parseHtml(html);
|
|
24988
25295
|
const tracks = new Set(parsed.elements.map((el) => el.zIndex));
|
|
@@ -25033,7 +25340,7 @@ var compositions_exports = {};
|
|
|
25033
25340
|
__export(compositions_exports, {
|
|
25034
25341
|
default: () => compositions_default
|
|
25035
25342
|
});
|
|
25036
|
-
import { readFileSync as
|
|
25343
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
25037
25344
|
function parseCompositions(html) {
|
|
25038
25345
|
const parser = new DOMParser();
|
|
25039
25346
|
const doc = parser.parseFromString(html, "text/html");
|
|
@@ -25090,7 +25397,7 @@ var init_compositions = __esm({
|
|
|
25090
25397
|
},
|
|
25091
25398
|
async run({ args }) {
|
|
25092
25399
|
const project = resolveProject(args.dir);
|
|
25093
|
-
const html =
|
|
25400
|
+
const html = readFileSync15(project.indexPath, "utf-8");
|
|
25094
25401
|
ensureDOMParser();
|
|
25095
25402
|
const compositions = parseCompositions(html);
|
|
25096
25403
|
if (compositions.length === 0) {
|
|
@@ -25126,7 +25433,7 @@ var benchmark_exports = {};
|
|
|
25126
25433
|
__export(benchmark_exports, {
|
|
25127
25434
|
default: () => benchmark_default
|
|
25128
25435
|
});
|
|
25129
|
-
import { existsSync as
|
|
25436
|
+
import { existsSync as existsSync28, statSync as statSync11 } from "fs";
|
|
25130
25437
|
import { resolve as resolve15, join as join26 } from "path";
|
|
25131
25438
|
var DEFAULT_CONFIGS, benchmark_default;
|
|
25132
25439
|
var init_benchmark = __esm({
|
|
@@ -25211,7 +25518,7 @@ var init_benchmark = __esm({
|
|
|
25211
25518
|
await producer.executeRenderJob(job, project.dir, outputPath);
|
|
25212
25519
|
const elapsedMs = Date.now() - startTime;
|
|
25213
25520
|
let fileSize = null;
|
|
25214
|
-
if (
|
|
25521
|
+
if (existsSync28(outputPath)) {
|
|
25215
25522
|
const stat = statSync11(outputPath);
|
|
25216
25523
|
fileSize = stat.size;
|
|
25217
25524
|
}
|
|
@@ -25420,7 +25727,7 @@ var docs_exports = {};
|
|
|
25420
25727
|
__export(docs_exports, {
|
|
25421
25728
|
default: () => docs_default
|
|
25422
25729
|
});
|
|
25423
|
-
import { readFileSync as
|
|
25730
|
+
import { readFileSync as readFileSync16, existsSync as existsSync29 } from "fs";
|
|
25424
25731
|
import { resolve as resolve16, dirname as dirname14, join as join27 } from "path";
|
|
25425
25732
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
25426
25733
|
function docsDir() {
|
|
@@ -25428,7 +25735,7 @@ function docsDir() {
|
|
|
25428
25735
|
const dir = dirname14(thisFile);
|
|
25429
25736
|
const devPath = resolve16(dir, "..", "docs");
|
|
25430
25737
|
const builtPath = resolve16(dir, "docs");
|
|
25431
|
-
return
|
|
25738
|
+
return existsSync29(devPath) ? devPath : builtPath;
|
|
25432
25739
|
}
|
|
25433
25740
|
function formatInlineCode(line) {
|
|
25434
25741
|
return line.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
|
|
@@ -25520,11 +25827,11 @@ var init_docs = __esm({
|
|
|
25520
25827
|
process.exit(1);
|
|
25521
25828
|
}
|
|
25522
25829
|
const filePath = join27(docsDir(), entry.file);
|
|
25523
|
-
if (!
|
|
25830
|
+
if (!existsSync29(filePath)) {
|
|
25524
25831
|
console.error(c.error(`Doc file not found: ${filePath}`));
|
|
25525
25832
|
process.exit(1);
|
|
25526
25833
|
}
|
|
25527
|
-
const content =
|
|
25834
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
25528
25835
|
console.log();
|
|
25529
25836
|
renderMarkdown(content);
|
|
25530
25837
|
}
|
|
@@ -25538,6 +25845,7 @@ __export(doctor_exports, {
|
|
|
25538
25845
|
default: () => doctor_default
|
|
25539
25846
|
});
|
|
25540
25847
|
import { execSync as execSync3 } from "child_process";
|
|
25848
|
+
import { freemem as freemem4, platform as platform3 } from "os";
|
|
25541
25849
|
function checkFFmpeg() {
|
|
25542
25850
|
const path = findFFmpeg();
|
|
25543
25851
|
if (path) {
|
|
@@ -25615,6 +25923,67 @@ function checkVersion() {
|
|
|
25615
25923
|
function checkNode() {
|
|
25616
25924
|
return { ok: true, detail: `${process.version} (${process.platform} ${process.arch})` };
|
|
25617
25925
|
}
|
|
25926
|
+
function checkCPU() {
|
|
25927
|
+
const sys = getSystemMeta();
|
|
25928
|
+
const model = sys.cpu_model ?? "Unknown";
|
|
25929
|
+
const speedStr = sys.cpu_speed ? ` @ ${sys.cpu_speed}MHz` : "";
|
|
25930
|
+
return { ok: true, detail: `${sys.cpu_count} cores \xB7 ${model}${speedStr}` };
|
|
25931
|
+
}
|
|
25932
|
+
function checkMemory() {
|
|
25933
|
+
const sys = getSystemMeta();
|
|
25934
|
+
const freeMb = bytesToMb(freemem4());
|
|
25935
|
+
const totalGb = (sys.memory_total_mb / 1024).toFixed(1);
|
|
25936
|
+
const freeGb = (freeMb / 1024).toFixed(1);
|
|
25937
|
+
if (freeMb < 2048) {
|
|
25938
|
+
return {
|
|
25939
|
+
ok: false,
|
|
25940
|
+
detail: `${totalGb} GB total \xB7 ${freeGb} GB free`,
|
|
25941
|
+
hint: "Low memory \u2014 renders may fail. Close other apps or increase RAM."
|
|
25942
|
+
};
|
|
25943
|
+
}
|
|
25944
|
+
return { ok: true, detail: `${totalGb} GB total \xB7 ${freeGb} GB free` };
|
|
25945
|
+
}
|
|
25946
|
+
function checkShm() {
|
|
25947
|
+
const shmMb = getShmSizeMb();
|
|
25948
|
+
if (shmMb === null) {
|
|
25949
|
+
return { ok: true, detail: "N/A (non-Linux)" };
|
|
25950
|
+
}
|
|
25951
|
+
if (shmMb < 256) {
|
|
25952
|
+
return {
|
|
25953
|
+
ok: false,
|
|
25954
|
+
detail: `${shmMb} MB`,
|
|
25955
|
+
hint: "Chrome needs \u2265256 MB. Use: docker run --shm-size=512m"
|
|
25956
|
+
};
|
|
25957
|
+
}
|
|
25958
|
+
return { ok: true, detail: `${shmMb} MB` };
|
|
25959
|
+
}
|
|
25960
|
+
function checkDisk() {
|
|
25961
|
+
const freeMb = getFreeDiskMb(".");
|
|
25962
|
+
if (freeMb === null) {
|
|
25963
|
+
return { ok: true, detail: "Unable to check" };
|
|
25964
|
+
}
|
|
25965
|
+
const freeGb = (freeMb / 1024).toFixed(1);
|
|
25966
|
+
if (freeMb < 1024) {
|
|
25967
|
+
return {
|
|
25968
|
+
ok: false,
|
|
25969
|
+
detail: `${freeGb} GB free`,
|
|
25970
|
+
hint: "Low disk space \u2014 renders produce large temp files."
|
|
25971
|
+
};
|
|
25972
|
+
}
|
|
25973
|
+
return { ok: true, detail: `${freeGb} GB free` };
|
|
25974
|
+
}
|
|
25975
|
+
function checkEnvironment() {
|
|
25976
|
+
const sys = getSystemMeta();
|
|
25977
|
+
const parts = [];
|
|
25978
|
+
if (sys.is_docker) parts.push("Docker");
|
|
25979
|
+
if (sys.is_wsl) parts.push("WSL");
|
|
25980
|
+
if (sys.is_ci) parts.push(`CI (${sys.ci_name ?? "detected"})`);
|
|
25981
|
+
if (!sys.is_tty) parts.push("non-TTY");
|
|
25982
|
+
if (parts.length === 0) {
|
|
25983
|
+
return { ok: true, detail: "Native terminal" };
|
|
25984
|
+
}
|
|
25985
|
+
return { ok: true, detail: parts.join(" \xB7 ") };
|
|
25986
|
+
}
|
|
25618
25987
|
var doctor_default;
|
|
25619
25988
|
var init_doctor = __esm({
|
|
25620
25989
|
"src/commands/doctor.ts"() {
|
|
@@ -25625,6 +25994,7 @@ var init_doctor = __esm({
|
|
|
25625
25994
|
init_ffmpeg();
|
|
25626
25995
|
init_version();
|
|
25627
25996
|
init_updateCheck();
|
|
25997
|
+
init_system();
|
|
25628
25998
|
doctor_default = defineCommand({
|
|
25629
25999
|
meta: { name: "doctor", description: "Check system dependencies and environment" },
|
|
25630
26000
|
args: {},
|
|
@@ -25635,12 +26005,21 @@ var init_doctor = __esm({
|
|
|
25635
26005
|
const checks = [
|
|
25636
26006
|
{ name: "Version", run: checkVersion },
|
|
25637
26007
|
{ name: "Node.js", run: checkNode },
|
|
26008
|
+
{ name: "CPU", run: checkCPU },
|
|
26009
|
+
{ name: "Memory", run: checkMemory },
|
|
26010
|
+
{ name: "Disk", run: checkDisk }
|
|
26011
|
+
];
|
|
26012
|
+
if (platform3() === "linux") {
|
|
26013
|
+
checks.push({ name: "/dev/shm", run: checkShm });
|
|
26014
|
+
}
|
|
26015
|
+
checks.push(
|
|
26016
|
+
{ name: "Environment", run: checkEnvironment },
|
|
25638
26017
|
{ name: "FFmpeg", run: checkFFmpeg },
|
|
25639
26018
|
{ name: "FFprobe", run: checkFFprobe },
|
|
25640
26019
|
{ name: "Chrome", run: checkChrome },
|
|
25641
26020
|
{ name: "Docker", run: checkDocker },
|
|
25642
26021
|
{ name: "Docker running", run: checkDockerRunning }
|
|
25643
|
-
|
|
26022
|
+
);
|
|
25644
26023
|
let allOk = true;
|
|
25645
26024
|
for (const check of checks) {
|
|
25646
26025
|
const result = await check.run();
|
|
@@ -25839,6 +26218,7 @@ init_version();
|
|
|
25839
26218
|
init_config();
|
|
25840
26219
|
init_client();
|
|
25841
26220
|
init_events();
|
|
26221
|
+
init_system();
|
|
25842
26222
|
|
|
25843
26223
|
// src/cli.ts
|
|
25844
26224
|
init_updateCheck();
|