storyforge 0.6.0 → 0.7.0
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/bridge-poller-JIP6RGMN.js +7033 -0
- package/dist/chunk-2UXQZTSS.js +877 -0
- package/dist/chunk-3ZW2KMKN.js +5657 -0
- package/dist/chunk-56OB3EDN.js +29 -0
- package/dist/chunk-62PNWAA7.js +1020 -0
- package/dist/chunk-C5KB4UV6.js +242 -0
- package/dist/chunk-CDQ3UP6J.js +52 -0
- package/dist/chunk-CQ2IV4Q2.js +14 -0
- package/dist/chunk-L4BNY5R3.js +175 -0
- package/dist/chunk-M6JAFPDI.js +314 -0
- package/dist/chunk-NSPRIPOP.js +36 -0
- package/dist/chunk-U6LFS35L.js +62 -0
- package/dist/chunk-WVPXYQ2G.js +164 -0
- package/dist/chunk-YLY3P6CS.js +39 -0
- package/dist/chunk-ZHDWKDF5.js +44 -0
- package/dist/{cli-usage-FG3YUG3W.js → cli-usage-G762TREV.js} +1 -0
- package/dist/dist-es-2LINLMXN.js +89 -0
- package/dist/dist-es-4NQJAKNU.js +381 -0
- package/dist/dist-es-4RCBWWWT.js +71 -0
- package/dist/dist-es-JQWJEY7F.js +490 -0
- package/dist/dist-es-KZQIITSZ.js +168 -0
- package/dist/dist-es-QJ3UEHQZ.js +325 -0
- package/dist/dist-es-SXKTBYGM.js +47 -0
- package/dist/event-streams-DNC7XM6J.js +245 -0
- package/dist/index.js +339 -7
- package/dist/loadSso-SM6TYICZ.js +591 -0
- package/dist/signin-TZJIHAWM.js +703 -0
- package/dist/sso-oidc-MO5NOHP3.js +828 -0
- package/dist/stitch-7XB7ZA4D.js +446 -0
- package/dist/sts-PUI4IC7G.js +3942 -0
- package/package.json +2 -2
- package/dist/bridge-poller-MM6K2GKM.js +0 -451
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
log
|
|
4
4
|
} from "./chunk-GJQ45C5W.js";
|
|
5
|
+
import "./chunk-NSPRIPOP.js";
|
|
5
6
|
|
|
6
7
|
// src/commands/dev.ts
|
|
7
8
|
import * as fs2 from "fs";
|
|
@@ -840,7 +841,7 @@ async function devCommand(options) {
|
|
|
840
841
|
}
|
|
841
842
|
void (async () => {
|
|
842
843
|
try {
|
|
843
|
-
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-
|
|
844
|
+
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-G762TREV.js");
|
|
844
845
|
const report = await gatherCliUsage();
|
|
845
846
|
const g = global;
|
|
846
847
|
g.__forgeCliUsageCache = { at: Date.now(), ver: CLI_USAGE_PARSER_VERSION, data: report };
|
|
@@ -876,7 +877,7 @@ async function devCommand(options) {
|
|
|
876
877
|
const pathname = url.pathname;
|
|
877
878
|
if (pathname === "/api/cli-usage") {
|
|
878
879
|
try {
|
|
879
|
-
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-
|
|
880
|
+
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-G762TREV.js");
|
|
880
881
|
const g = global;
|
|
881
882
|
const now = Date.now();
|
|
882
883
|
if (g.__forgeCliUsageCache && g.__forgeCliUsageCache.ver === CLI_USAGE_PARSER_VERSION && now - g.__forgeCliUsageCache.at < 3e4) {
|
|
@@ -1614,7 +1615,7 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
|
|
|
1614
1615
|
return "0.0.0";
|
|
1615
1616
|
})();
|
|
1616
1617
|
void (async () => {
|
|
1617
|
-
const { BridgePoller } = await import("./bridge-poller-
|
|
1618
|
+
const { BridgePoller } = await import("./bridge-poller-JIP6RGMN.js");
|
|
1618
1619
|
const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken, clientVersion: `storyforge ${pkgVersion}` });
|
|
1619
1620
|
poller.start();
|
|
1620
1621
|
})();
|
|
@@ -1678,15 +1679,329 @@ async function loginCommand() {
|
|
|
1678
1679
|
}
|
|
1679
1680
|
}
|
|
1680
1681
|
|
|
1682
|
+
// src/commands/doctor.ts
|
|
1683
|
+
import { spawn as spawn2 } from "child_process";
|
|
1684
|
+
import { promisify as promisify2 } from "util";
|
|
1685
|
+
import { execFile as execFileCb } from "child_process";
|
|
1686
|
+
import os3 from "os";
|
|
1687
|
+
var execFile2 = promisify2(execFileCb);
|
|
1688
|
+
async function runDoctor() {
|
|
1689
|
+
const platform = os3.platform();
|
|
1690
|
+
const arch = os3.arch();
|
|
1691
|
+
const cores = os3.cpus().length;
|
|
1692
|
+
const ramGb = Math.round(os3.totalmem() / 1024 ** 3);
|
|
1693
|
+
const renderers = await Promise.all([
|
|
1694
|
+
checkFfmpeg(platform),
|
|
1695
|
+
checkPython(),
|
|
1696
|
+
checkManim(),
|
|
1697
|
+
checkHyperframes(),
|
|
1698
|
+
checkChromeHeadlessShell(platform),
|
|
1699
|
+
checkNode(),
|
|
1700
|
+
checkNpm()
|
|
1701
|
+
]);
|
|
1702
|
+
const ready = renderers.filter((r) => r.required).every((r) => r.installed);
|
|
1703
|
+
return { platform, arch, cores, ramGb, renderers, ready };
|
|
1704
|
+
}
|
|
1705
|
+
function formatDoctorReport(r) {
|
|
1706
|
+
const lines = [];
|
|
1707
|
+
lines.push(`storyforge doctor`);
|
|
1708
|
+
lines.push(` platform: ${r.platform} \xB7 ${r.arch} \xB7 ${r.cores} cores \xB7 ${r.ramGb} GB RAM`);
|
|
1709
|
+
lines.push("");
|
|
1710
|
+
for (const dep of r.renderers) {
|
|
1711
|
+
const tick = dep.installed ? "\x1B[32m\u2713\x1B[0m" : dep.required ? "\x1B[31m\u2717\x1B[0m" : "\x1B[33m\u25CB\x1B[0m";
|
|
1712
|
+
const ver = dep.version ? ` (${dep.version})` : "";
|
|
1713
|
+
const need = dep.required ? "" : " [optional]";
|
|
1714
|
+
lines.push(` ${tick} ${dep.name.padEnd(28)}${ver}${need}`);
|
|
1715
|
+
if (!dep.installed && dep.installCommand) {
|
|
1716
|
+
lines.push(` install: ${dep.installCommand}`);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
lines.push("");
|
|
1720
|
+
if (r.ready) {
|
|
1721
|
+
lines.push(`\x1B[32m\u2713 ready to render.\x1B[0m next: \`storyforge\` to start the bridge.`);
|
|
1722
|
+
} else {
|
|
1723
|
+
lines.push(`\x1B[33m! missing required renderers.\x1B[0m run: \`storyforge install-renderers\` to install them.`);
|
|
1724
|
+
}
|
|
1725
|
+
return lines.join("\n");
|
|
1726
|
+
}
|
|
1727
|
+
async function probeVersion(cmd, args = ["--version"], parser = firstLine) {
|
|
1728
|
+
try {
|
|
1729
|
+
const { stdout, stderr } = await execFile2(cmd, args, { timeout: 5e3 });
|
|
1730
|
+
const out = (stdout || stderr || "").trim();
|
|
1731
|
+
return { installed: true, version: parser(out) };
|
|
1732
|
+
} catch {
|
|
1733
|
+
return { installed: false, version: null };
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
function firstLine(s) {
|
|
1737
|
+
return s.split("\n")[0]?.trim().slice(0, 80) ?? null;
|
|
1738
|
+
}
|
|
1739
|
+
async function checkFfmpeg(platform) {
|
|
1740
|
+
const probe = await probeVersion("ffmpeg", ["-version"], (s) => {
|
|
1741
|
+
const m = s.match(/ffmpeg version (\S+)/);
|
|
1742
|
+
return m?.[1] ?? null;
|
|
1743
|
+
});
|
|
1744
|
+
return {
|
|
1745
|
+
name: "ffmpeg",
|
|
1746
|
+
installed: probe.installed,
|
|
1747
|
+
version: probe.version,
|
|
1748
|
+
rationale: "concat + audio mux + watermark \u2014 required by every engine",
|
|
1749
|
+
installCommand: platform === "darwin" ? "brew install ffmpeg" : platform === "linux" ? "sudo apt install -y ffmpeg" : "https://ffmpeg.org/download.html",
|
|
1750
|
+
required: true
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
async function checkPython() {
|
|
1754
|
+
const probe = await probeVersion("python3", ["--version"], (s) => {
|
|
1755
|
+
const m = s.match(/Python (\S+)/);
|
|
1756
|
+
return m?.[1] ?? null;
|
|
1757
|
+
});
|
|
1758
|
+
return {
|
|
1759
|
+
name: "python3",
|
|
1760
|
+
installed: probe.installed,
|
|
1761
|
+
version: probe.version,
|
|
1762
|
+
rationale: "manim engine runtime",
|
|
1763
|
+
installCommand: os3.platform() === "darwin" ? "brew install python@3.12" : "sudo apt install -y python3",
|
|
1764
|
+
required: false
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
async function checkManim() {
|
|
1768
|
+
const probe = await new Promise((resolve3) => {
|
|
1769
|
+
const p = spawn2("python3", ["-m", "manim", "--version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
1770
|
+
let stdout = "";
|
|
1771
|
+
let stderr = "";
|
|
1772
|
+
p.stdout.on("data", (d) => {
|
|
1773
|
+
stdout += d.toString("utf8");
|
|
1774
|
+
});
|
|
1775
|
+
p.stderr.on("data", (d) => {
|
|
1776
|
+
stderr += d.toString("utf8");
|
|
1777
|
+
});
|
|
1778
|
+
p.on("error", () => resolve3({ installed: false, version: null }));
|
|
1779
|
+
p.on("close", (code) => {
|
|
1780
|
+
if (code === 0) {
|
|
1781
|
+
const m = (stdout + stderr).match(/Manim Community v(\S+)/);
|
|
1782
|
+
resolve3({ installed: true, version: m?.[1] ?? null });
|
|
1783
|
+
} else {
|
|
1784
|
+
resolve3({ installed: false, version: null });
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
setTimeout(() => {
|
|
1788
|
+
p.kill();
|
|
1789
|
+
resolve3({ installed: false, version: null });
|
|
1790
|
+
}, 5e3);
|
|
1791
|
+
});
|
|
1792
|
+
return {
|
|
1793
|
+
name: "manim (python pkg)",
|
|
1794
|
+
installed: probe.installed,
|
|
1795
|
+
version: probe.version,
|
|
1796
|
+
rationale: "3Blue1Brown-style mathematical animations",
|
|
1797
|
+
installCommand: "python3 -m pip install --user manim",
|
|
1798
|
+
required: false
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
async function checkHyperframes() {
|
|
1802
|
+
const probe = await probeVersion("hyperframes", ["--version"]);
|
|
1803
|
+
return {
|
|
1804
|
+
name: "hyperframes",
|
|
1805
|
+
installed: probe.installed,
|
|
1806
|
+
version: probe.version,
|
|
1807
|
+
rationale: "GSAP / Three.js / Lottie cascades (Stage 2 engine)",
|
|
1808
|
+
installCommand: "npm install -g hyperframes",
|
|
1809
|
+
required: false
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
async function checkChromeHeadlessShell(platform) {
|
|
1813
|
+
if (platform !== "linux") {
|
|
1814
|
+
return {
|
|
1815
|
+
name: "chrome-headless-shell",
|
|
1816
|
+
installed: false,
|
|
1817
|
+
version: null,
|
|
1818
|
+
rationale: "hyperframes deterministic mode (Linux only \u2014 macOS uses screenshot fallback)",
|
|
1819
|
+
installCommand: null,
|
|
1820
|
+
required: false
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
const probe = await probeVersion("chrome-headless-shell", ["--version"]);
|
|
1824
|
+
return {
|
|
1825
|
+
name: "chrome-headless-shell",
|
|
1826
|
+
installed: probe.installed,
|
|
1827
|
+
version: probe.version,
|
|
1828
|
+
rationale: "hyperframes deterministic BeginFrame mode",
|
|
1829
|
+
installCommand: "npx puppeteer browsers install chrome-headless-shell",
|
|
1830
|
+
required: false
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
async function checkNode() {
|
|
1834
|
+
const probe = await probeVersion("node", ["--version"]);
|
|
1835
|
+
return {
|
|
1836
|
+
name: "node",
|
|
1837
|
+
installed: probe.installed,
|
|
1838
|
+
version: probe.version,
|
|
1839
|
+
rationale: "Remotion + JS pipeline runtime",
|
|
1840
|
+
installCommand: "https://nodejs.org/",
|
|
1841
|
+
required: true
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
async function checkNpm() {
|
|
1845
|
+
const probe = await probeVersion("npm", ["--version"]);
|
|
1846
|
+
return {
|
|
1847
|
+
name: "npm",
|
|
1848
|
+
installed: probe.installed,
|
|
1849
|
+
version: probe.version,
|
|
1850
|
+
rationale: "Remotion + hyperframes installer",
|
|
1851
|
+
installCommand: "comes with node",
|
|
1852
|
+
required: true
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
async function doctorCommand() {
|
|
1856
|
+
const report = await runDoctor();
|
|
1857
|
+
console.log(formatDoctorReport(report));
|
|
1858
|
+
process.exit(report.ready ? 0 : 1);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// src/commands/install-renderers.ts
|
|
1862
|
+
import { spawn as spawn3 } from "child_process";
|
|
1863
|
+
import readline2 from "readline/promises";
|
|
1864
|
+
import { stdin as input, stdout as output } from "process";
|
|
1865
|
+
import os4 from "os";
|
|
1866
|
+
function planInstall(missing, platform) {
|
|
1867
|
+
const steps = [];
|
|
1868
|
+
for (const r of missing) {
|
|
1869
|
+
if (r.installed) continue;
|
|
1870
|
+
switch (r.name) {
|
|
1871
|
+
case "ffmpeg": {
|
|
1872
|
+
if (platform === "darwin") {
|
|
1873
|
+
steps.push({ name: "ffmpeg", argv: ["brew", "install", "ffmpeg"], display: "brew install ffmpeg" });
|
|
1874
|
+
} else if (platform === "linux") {
|
|
1875
|
+
steps.push({ name: "ffmpeg", argv: ["sudo", "apt", "install", "-y", "ffmpeg"], display: "sudo apt install -y ffmpeg" });
|
|
1876
|
+
} else {
|
|
1877
|
+
steps.push({ name: "ffmpeg", argv: null, display: r.installCommand ?? "see ffmpeg.org", manual: true });
|
|
1878
|
+
}
|
|
1879
|
+
break;
|
|
1880
|
+
}
|
|
1881
|
+
case "python3": {
|
|
1882
|
+
if (platform === "darwin") {
|
|
1883
|
+
steps.push({ name: "python3", argv: ["brew", "install", "python@3.12"], display: "brew install python@3.12" });
|
|
1884
|
+
} else if (platform === "linux") {
|
|
1885
|
+
steps.push({ name: "python3", argv: ["sudo", "apt", "install", "-y", "python3", "python3-pip"], display: "sudo apt install -y python3 python3-pip" });
|
|
1886
|
+
} else {
|
|
1887
|
+
steps.push({ name: "python3", argv: null, display: "install Python 3 from python.org", manual: true });
|
|
1888
|
+
}
|
|
1889
|
+
break;
|
|
1890
|
+
}
|
|
1891
|
+
case "manim (python pkg)": {
|
|
1892
|
+
steps.push({ name: "manim (python pkg)", argv: ["python3", "-m", "pip", "install", "--user", "manim"], display: "python3 -m pip install --user manim" });
|
|
1893
|
+
break;
|
|
1894
|
+
}
|
|
1895
|
+
case "hyperframes": {
|
|
1896
|
+
steps.push({ name: "hyperframes", argv: ["npm", "install", "-g", "hyperframes"], display: "npm install -g hyperframes" });
|
|
1897
|
+
break;
|
|
1898
|
+
}
|
|
1899
|
+
case "chrome-headless-shell": {
|
|
1900
|
+
if (platform === "linux") {
|
|
1901
|
+
steps.push({ name: "chrome-headless-shell", argv: ["npx", "puppeteer", "browsers", "install", "chrome-headless-shell"], display: "npx puppeteer browsers install chrome-headless-shell" });
|
|
1902
|
+
}
|
|
1903
|
+
break;
|
|
1904
|
+
}
|
|
1905
|
+
case "node":
|
|
1906
|
+
case "npm":
|
|
1907
|
+
steps.push({ name: r.name, argv: null, display: r.installCommand ?? "install Node.js from nodejs.org", manual: true });
|
|
1908
|
+
break;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
return steps;
|
|
1912
|
+
}
|
|
1913
|
+
async function ask(rl, question) {
|
|
1914
|
+
const ans = (await rl.question(question)).trim().toLowerCase();
|
|
1915
|
+
return ans === "" || ans === "y" || ans === "yes";
|
|
1916
|
+
}
|
|
1917
|
+
function runStep(argv) {
|
|
1918
|
+
return new Promise((resolve3) => {
|
|
1919
|
+
const [cmd, ...args] = argv;
|
|
1920
|
+
const proc = spawn3(cmd, args, { stdio: ["inherit", "inherit", "inherit"] });
|
|
1921
|
+
proc.on("error", (err) => resolve3({ ok: false, tail: err.message }));
|
|
1922
|
+
proc.on("close", (code) => resolve3({ ok: code === 0 }));
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
async function installRenderersCommand(opts = {}) {
|
|
1926
|
+
console.log("\x1B[1mstoryforge install-renderers\x1B[0m\n");
|
|
1927
|
+
const report = await runDoctor();
|
|
1928
|
+
const missing = report.renderers.filter((r) => !r.installed && r.installCommand);
|
|
1929
|
+
if (missing.length === 0) {
|
|
1930
|
+
console.log("\x1B[32m\u2713 all renderers already installed.\x1B[0m");
|
|
1931
|
+
process.exit(0);
|
|
1932
|
+
}
|
|
1933
|
+
const steps = planInstall(missing, report.platform);
|
|
1934
|
+
if (steps.length === 0) {
|
|
1935
|
+
console.log("\x1B[33m! nothing to install on this platform \u2014 run `storyforge doctor` for the manual install hints.\x1B[0m");
|
|
1936
|
+
process.exit(1);
|
|
1937
|
+
}
|
|
1938
|
+
console.log(`Detected ${steps.length} missing renderer${steps.length === 1 ? "" : "s"}:`);
|
|
1939
|
+
for (const s of steps) {
|
|
1940
|
+
console.log(` \u2022 ${s.name.padEnd(28)} \u2192 ${s.display}${s.manual ? " [manual]" : ""}`);
|
|
1941
|
+
}
|
|
1942
|
+
console.log("");
|
|
1943
|
+
const rl = readline2.createInterface({ input, output });
|
|
1944
|
+
let installed = 0;
|
|
1945
|
+
let skipped = 0;
|
|
1946
|
+
let failed = [];
|
|
1947
|
+
try {
|
|
1948
|
+
for (const step of steps) {
|
|
1949
|
+
if (step.manual || !step.argv) {
|
|
1950
|
+
console.log(`\x1B[33m\u25B8 ${step.name}\x1B[0m \u2014 manual install: ${step.display}`);
|
|
1951
|
+
skipped++;
|
|
1952
|
+
continue;
|
|
1953
|
+
}
|
|
1954
|
+
const proceed = opts.yes ? true : await ask(rl, `Install \x1B[1m${step.name}\x1B[0m via \x1B[36m${step.display}\x1B[0m? [Y/n] `);
|
|
1955
|
+
if (!proceed) {
|
|
1956
|
+
console.log(` skipped ${step.name}.`);
|
|
1957
|
+
skipped++;
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
console.log(`
|
|
1961
|
+
\x1B[36m\u25B8 ${step.display}\x1B[0m`);
|
|
1962
|
+
const result = await runStep(step.argv);
|
|
1963
|
+
if (result.ok) {
|
|
1964
|
+
console.log(`\x1B[32m \u2713 ${step.name} installed.\x1B[0m
|
|
1965
|
+
`);
|
|
1966
|
+
installed++;
|
|
1967
|
+
} else {
|
|
1968
|
+
console.log(`\x1B[31m \u2717 ${step.name} install failed.\x1B[0m
|
|
1969
|
+
`);
|
|
1970
|
+
failed.push(step.name);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
} finally {
|
|
1974
|
+
rl.close();
|
|
1975
|
+
}
|
|
1976
|
+
console.log("");
|
|
1977
|
+
console.log(`Installed: ${installed} \xB7 Skipped: ${skipped} \xB7 Failed: ${failed.length}`);
|
|
1978
|
+
if (failed.length > 0) {
|
|
1979
|
+
console.log(`\x1B[31m failed: ${failed.join(", ")}\x1B[0m`);
|
|
1980
|
+
}
|
|
1981
|
+
console.log("\nRe-probing\u2026\n");
|
|
1982
|
+
const after = await runDoctor();
|
|
1983
|
+
const stillMissing = after.renderers.filter((r) => !r.installed && r.required);
|
|
1984
|
+
if (stillMissing.length === 0) {
|
|
1985
|
+
console.log("\x1B[32m\u2713 ready to render.\x1B[0m next: `storyforge` to start the bridge.");
|
|
1986
|
+
process.exit(0);
|
|
1987
|
+
} else {
|
|
1988
|
+
console.log(`\x1B[33m! still missing required: ${stillMissing.map((r) => r.name).join(", ")}\x1B[0m`);
|
|
1989
|
+
console.log(" run `storyforge doctor` to see install hints.");
|
|
1990
|
+
process.exit(1);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1681
1994
|
// src/index.ts
|
|
1682
|
-
var VERSION = "0.
|
|
1995
|
+
var VERSION = "0.7.0";
|
|
1683
1996
|
var HELP = `
|
|
1684
1997
|
storyforge \u2014 local bridge for the Forge video production web app
|
|
1685
1998
|
|
|
1686
1999
|
Usage:
|
|
1687
|
-
storyforge Auto-link current folder, start
|
|
1688
|
-
storyforge
|
|
1689
|
-
storyforge
|
|
2000
|
+
storyforge Auto-link current folder, start bridge, open browser (default)
|
|
2001
|
+
storyforge login Log in to forge.algo-thinker.com
|
|
2002
|
+
storyforge doctor Probe local renderers (ffmpeg / python / manim / hyperframes)
|
|
2003
|
+
storyforge install-renderers Install missing renderers (interactive, asks per-tool)
|
|
2004
|
+
storyforge install-renderers -y Same, but auto-confirm every prompt
|
|
1690
2005
|
storyforge --help Show this help
|
|
1691
2006
|
storyforge --version Show version
|
|
1692
2007
|
|
|
@@ -1695,6 +2010,14 @@ Options:
|
|
|
1695
2010
|
--dir <dir> Project directory (default: current)
|
|
1696
2011
|
--no-open Do not open browser automatically
|
|
1697
2012
|
|
|
2013
|
+
First-time setup:
|
|
2014
|
+
npm install -g storyforge
|
|
2015
|
+
storyforge login
|
|
2016
|
+
storyforge doctor # see what's missing
|
|
2017
|
+
storyforge install-renderers # ffmpeg + python + manim + hyperframes
|
|
2018
|
+
cd /path/to/your/project
|
|
2019
|
+
storyforge # links project, starts bridge, opens browser
|
|
2020
|
+
|
|
1698
2021
|
In any folder with assets (audio/, images-horizontal/, images-vertical/, scripts/),
|
|
1699
2022
|
just run: storyforge
|
|
1700
2023
|
`.trim();
|
|
@@ -1733,6 +2056,15 @@ async function main() {
|
|
|
1733
2056
|
await loginCommand();
|
|
1734
2057
|
return;
|
|
1735
2058
|
}
|
|
2059
|
+
if (firstArg === "doctor") {
|
|
2060
|
+
await doctorCommand();
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
if (firstArg === "install-renderers" || firstArg === "install") {
|
|
2064
|
+
const yes = args.includes("-y") || args.includes("--yes");
|
|
2065
|
+
await installRenderersCommand({ yes });
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
1736
2068
|
const opts = parseArgs(args);
|
|
1737
2069
|
await devCommand({
|
|
1738
2070
|
port: typeof opts.port === "string" ? opts.port : void 0,
|